I'm new to Laravel, and I got stuck with the following issue:
I have a table for the users, and groups, and a table for connecting them. The general task any user can join any group.
----------------------------------------------
| users | groups | user_groups |
|--------------------------------------------|
| id - int pk | id - pk | id - pk |
| name text | name | user_id - fk |
| email | | group_id - fk |
| phone | | any_attr |
----------------------------------------------
I have the following models:
class User
{
...
public function groups()
{
return $this->belongsToMany(Group::class, 'user_groups')->withPivot(['is_notification_requested']);
}
...
}
class Group
{
...
public function users()
{
return $this->belongsToMany(User::class, 'user_groups');
}
...
}
How do I get all of the groups, with a count of the members? I need the Group model, and a count of the users in the group.
If you're using Laravel 5.3, you can simply add withCount('relationship') as documented here: https://laravel.com/docs/5.3/eloquent-relationships#counting-related-models
Here's an example following your code:
$groups = Group::withCount('users')->get();
Now you can do this:
foreach($groups as $group) {
echo $group->user_count
}
Related
I'm struggling to connect three models in my Laravel app. The models are Bottle, Label and Spirit. I want to get all the labels based on bottle_id and spirit_id so I created a pivot table to store the relationships between Bottle-Label-Spirit. Please see below my current setup.
DB
+---------+--------+---------+-------------------------+
| bottles | labels | spirits | bottle_label_spirit |
+---------+--------+---------+-------------------------+
| id | id | id | id |
| name | name | name | bottle_id |
| | | | label_id |
| | | | spirit_id |
| | | | created_at |
| | | | updated_at |
+---------+--------+---------+-------------------------+
Where bottle_label_spirit is my pivot table
BOTTLE CLASS
class Bottle extends Model
{
public function labels() {
return $this->belongsToMany(Label::class)->withTimestamps();
}
public function spirits() {
return $this->belongsToMany(Spirit::class)->withTimestamps();
}
}
LABEL CLASS
class Label extends Model
{
public function bottles() {
return $this->belongsToMany(Bottle::class)->withTimestamps();
}
public function spirits() {
return $this->belongsToMany(Spirit::class)->withTimestamps();
}
}
SPIRIT CLASS
class Spirit extends Model
{
public function labels() {
return $this->belongsToMany(Label::class)->withTimestamps();
}
public function bottles() {
return $this->belongsToMany(Bottle::class)->withTimestamps();
}
}
QUESTIONS
So my questions are:
Is this the right approach to handle this manyToMany relationships?
If yes, how do i get all the labels where bottle_id = 1 and spirit_id = 1
You do not need a 4th table for this, you can accomplish all of this using hasManyThrough. This will allow you to query distant relationships.
I have a sponsorship app I'm creating and trying to get a pivot table working between my users and kids, but when I have a user sponsor a kid, the pivot table kid_user is not populated with the kid_id or the user_id. Not sure what I'm missing.
A Kid can have as many users (sponsors) as their slots allow them.
Users can sponsor a kid, multiple kids or the same kid multiple times
if needed.
Here is my kid_user pivot table:
public function up()
{
Schema::create('kid_user', function (Blueprint $table) {
$table->integer('kid_id')->unsigned()->index();
$table->foreign('kid_id')->references('id')->on('kids')->onDelete('cascade');
$table->integer('user_id')->unsigned()->index();
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
$table->primary(['kid_id', 'user_id']);
});
}
Then on the User model: The user can have many kids...
public function kid()
{
return $this->hasMany(Kid::class);
}
Then on the Kid model: The kids can have many users...
public function user() {
//return $this->belongsTo(User::class); (Tried this..)
return $this->hasMany(User::class);
}
Here are the tables I'm using. (Only relevant info is included in the tables)
+---------------------+
| Tables_in_Database |
+---------------------+
| kid_user |
| kids |
| users |
+---------------------+
+-----------------------------+
| users table |
+----+------------+-----------+
| id | first_name | last_name |
+----+------------+-----------+
| 1 | John | Smith |
| 2 | Jane | Doe |
+----+------------+-----------+
+-----------------------------+
| kids table |
+----+------------+-----------+-------+
| id | first_name | last_name | slots |
+----+------------+-----------+-------+
| 1 | Bobby | Little | 3 | -> Can be sponsored 3 times
+----+------------+-----------+-------+
+--------------------+
| kid_user table | THE BELOW RESULTS ARE WHAT I'M LOOKING FOR.
+--------------------+
| *kid_id | *user_id | * = Primary Key
+---------+----------+
| 1 | 1 | -> Sponsored 1st Slot
+---------+----------+
| 1 | 2 | -> Sponsored 2nd Slot
+---------+----------+
| 1 | 1 | -> Sponsored 3rd Slot
+---------+----------+
So when a User sponsors a Kid. I would like the kid_id & user_id to be entered into the kid_user pivot table. Any help would be appreciated.
First of all you might wanna rename the functions in your models in plural as it does not have one but many from the relationship.
So in your user model add this:
public function kids()
{
return $this->belongsToMany(Kid::class);
}
And in your Kid model:
public function users()
{
return $this->belongsToMany(User::class);
}
Then in order to save to the pivot table since your table naming is correct, just doing:
$user->kids()->attach($kid);
Will save it properly in the pivot table. Making sure first that you have existing User and Kid for the variables. More details here
I have Two Table
1- projects
User with id 5 has created 3 project - which means he will have 3 unique conversation with our different agent
----------------------------------------
|id | user_id | title | time |
|1 | 5 | Example | 2018-06-30 |
|2 | 5 | Example | 2018-06-30 |
|3 | 5 | Example | 2018-06-30 |
----------------------------------------
2- conversation
-------------------------------------------
|id | project_id | user_one | user_two |
|1 | 1 | 5 | 3 |
|2 | 2 | 5 | 7 |
|3 | 3 | 5 | 10 |
-------------------------------------------
Whenever a project is created, a conversation is created with that project id, Now in Laravel i want to get that project detail using Eloquent Relationships.
User_one is the project creator and user_two is our agent assigned to that product.
This is What I've tried
class Chat extends Model {
public function project()
{
return $this->belongsTo('App\ProjectModel');
}
}
class ProjectModel extends Model
{
public $table = 'projects';
}
Here is the controller function
public function Progress($id){ // Id passed here is 2, so it should show detail of project number 2
return \App\Chat::find($id)->project()->get();
}
After all this I'm getting an error - Call to a member function project() on null
You can try like this with creating 2 Models Project and Conversation
table
conversations(id, project_id, creator, agent)
Project Model
public function conversations(){
return $this->hasMany('App\Conversation');
}
Conversation Model
public function project(){
return $this->belongsTo('App\Project', 'project_id');
}
public function creatorUser(){
return $this->belongsTo('App\User', 'creator');
}
public function agentUser(){
return $this->belongsTo('App\User', 'agent');
}
Fetch Data
public function Progress($id){ // Id passed here is 2, so it should show detail of project number 2
$chats = Conversation::with('project', 'creatorUser', 'agentUser')->where('project_id', 2)->get();
foreach($chats as $chat){
dd($chat->project); //it will always print same project because we have filter the conversation by project_id
dd($chat->creatorUser);
dd($chat->agentUser);
}
}
you can create a relation Along with specifying foreign Key and owner key like:
class Chat extends Model {
public function project()
{
return $this->belongsTo(App\ProjectModel::class, 'project_id', 'id');
}
}
and then you will be able to get:
\App\Chat::where('id', $id)->first()->project;
Problem
I created a simple friendship relationship for my Laravel app which all worked ok until I noticed that when I queried the friendship of a user it would only search the current user on the UID1 field.
Since friendships are in essence a two-way relationship, Im trying to find a way in a laravel Model to retrieve ALL friendships relations by multiple columns.
Current Implementation
public function friends()
{
return $this->belongsToMany( App\Modules\Users\Models\User::class ,'friends', 'uid1');
}
Ideal Implementation
public function friends()
{
$a = $this->belongsToMany( App\Modules\Users\Models\User::class ,'users_friends', 'uid1');
$b = $this->belongsToMany( App\Modules\Users\Models\User::class ,'users_friends', 'uid2');
return combine($a,$b);
}
Table Structure
+----------------------+
| users table |
+----------------------+
+----| id: primary UserID |
| | fname: string |
| +----------------------+
|
|
| +----------------------+
| | friends table |
| +----------------------+
| | id: primary iD |
| | |
+----| uid1: user_id |
| | |
+----| uid2: user_id |
+----------------------+
The current implementation will only result in 1 of these records returning if the Current UserID = 1 as per the data in the friends table below.
+-------------------------------+
| friends table (data) |
+--------|---------|------------+
| id | uid1 | uid2 |
+--------|---------|------------+
| 1 | 1 | 7 |
| 2 | 7 | 1 |
| 3 | 9 | 1 |
+-------------------------------+
User Model
<?php
namespace App\Modules\Users\Models;
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
protected $table = 'users';
protected $fillable = [
'username', 'email', 'password', .... .
];
public function friends()
{
return $this->belongsToMany( App\Modules\Users\Models\User::class ,'users_friends', 'uid1');
}
Environment
Server = Homestead/linux
PHP = 7
MySQL
Update
I have a FriendShip helper class I created which does something similar, however in this function I pass in the UserID explicitly
Friendship::where( [
[ 'uid1' ,'=', $uid],
])->orWhere( [
[ 'uid2', '=', $uid]
])->all();
You can add additional conditions when you're declaring relationship by simply chaining it.
<?php
//...
class User extends Model {
//...
public function friends() {
return $this->hasMany(/*...*/)->orWhere('uid2', $this->id);
}
//...
But keep in mind that eloquent is not grouping the first conditions of relation in parenthesis so you might end with SQL that will not work as expected in some cases (if using or, and should be fine)
For example the above might result in a SQL that looks like this
SELECT * FROM users_friends WHERE uid1 = ? AND uid1 IS NOT NULL OR uid2 = ?
Which is a correct SQL statement but without grouping you will not get the result that you're expecting.
Another way is to use accessor and two separate relationships
<?php
//...
public function friends1() {
return $this->belongsToMany(User::class, 'users_friends', 'uid1');
}
public function friends2() {
return $this->belongsToMany(User::class, 'users_friends', 'uid2');
}
public function getFriendsAttribute() {
return $this->friends1->merge($this->friends2);
}
//...
But this way you get two separate trips to DB.
I'm trying to get the output of a belongstoMany relationship between users and sections database, which are tied to User and Section model, respectively.
User model has this method:
public function section()
{
return $this->belongsToMany('App\Models\Section','user_section')->withTimestamps();
}
Section model has this method:
public function user()
{
return $this->belongsToMany('App\Models\User','user_section')->withTimestamps();
}
My user_section table looks like this:
+----+---------+------------+------------+------------+
| id | user_id | section_id | created_at | updated_at |
+----+---------+------------+------------+------------+
| 1 | 1 | 1 | NULL | NULL |
| 2 | 2 | 1 | NULL | NULL |
+----+---------+------------+------------+------------+
2 rows in set (0.00 sec)
So why when I do this in the business logic:
$user = User::where("id",Auth::user()->id)->first(); //user with id of 1 in my case
return json_encode($user->section());
Do I get {} as output?
$user->section() will return the BelongsToMany relationship instead of the model object itself. You can do $user->section instead to load the relationship and have the model returned.