Query data based on pivot table - laravel

I have a database design which essentially takes the following form (I have removed a lot of fields as they are not really needed for demonstration purposes). I have a users table
users
+----+---------------+-----------------+
| id | name | email |
+----+---------------+-----------------+
| 1 | ProjectA | Something |
+----+---------------+-----------------+
A user can have many projects
projects
+----+---------------+-----------------+-----------------+
| id | name | description | user_id |
+----+---------------+-----------------+-----------------+
| 1 | ProjectA | Something | 1 |
+----+---------------+-----------------+-----------------+
So that is straight forward enough and very easy to query. If I want all projects for the logged in user I can do
$loggedInUser = Auth::user()->getFirstName() . ' ' . Auth::user()->getLastName();
$loggedInUserId = User::where('userName', '=', $loggedInUser)->first();
$projectss = Project::all()->where('user_id', $loggedInUserId);
This is where things get a little more tricky. I have a pivot table for a users groups. It is essentially this
users_user_groups
+----+---------------+-----------------+
| id | user_id | group_id |
+----+---------------+-----------------+
| 1 | 1 | 2 |
+----+---------------+-----------------+
I then have a user_groups table
user_groups
+----+---------------+
| id | group_name |
+----+---------------+
| 1 | Group A |
+----+---------------+
If I want to find what groups a user is a part of I can do
$userGroups = Auth::user()->getGroups();
My question is this. Above, I demonstrate how I can get all projects for a user. Now I know there is a user_group called Group A. What I essentially want to do is get all projects where the user is apart of Group A. So if 5 users create a project and they are all in Group A, then I should be returned 5 projects.
How would I go about doing something like this?
Thanks

Firstly you can get user id using simply Auth::user()->id
Assuming you are trying to get all the projects that belongs to users of a group You can do this.
$group = Group::with('users.projects')->find(1);
Group model
public function users()
{
return $this->belongsToMany('App\User');
}
User Model
public function projects()
{
return $this->hasMany('App\Project');
}
Of course you would have to make the appropriate relation methods depending on the forign/primary keys you used.

Related

Laravel many to many 2 level down pivot table

I am trying to build a Survey Module in Laravel where user can create survey, assign questions and options to the questions in survey.
survey can have multiple questions
survey question can have multiple options
To meet the above requirement I created the following models & tables
Model: Question
Table: questions
| id | question |
| -------- | -------------------------|
| 1 | How is the performance? |
| 2 | How did you know about us|
Model: Option
Table: options
| id | option |
| --- | --------- |
| 1 | Good |
| 2 | Bad |
| 3 | Google |
| 2 | SMS |
Now the relationship between questions and survey will be stored in pivot table
Model: SurveyQuestion
Table: survey_questions
| id | survey_id| question_id |
| ---| -------- |-------------|
| 1 | 1 |1 |
| 1 | 1 |2 |
Upto this point I know how to store data into pivot table using attach/sync.
Now the problem is As per requirement each survey question might have multiple options so I created another pivot table survey_question_option in which I am using survey_questions primary key as foreign key.
Model: SurveyQuestionOption
Table: survey_question_options
| id | survey_question_id| option_id |
| -- | ----------------- |-----------|
| 1 | 1 |1 |
| 1 | 1 |2 |
Now my question is that is it correct to use pivot table primary key as foreign key into another table?
If yes then how can I store data into survey_question_options table using laravel relationships?
If no then what is the better solution?
In this case you can create a Custom Intermediate Table Model (Custom Pivot)
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Relations\Pivot;
class SurveyQuestion extends Pivot
{
public function options()
{
//You need to create a pivot pivot table survey_question_option
//with (survey_question_id, option_id)
return $this->belongsToMany(Option::class, 'survey_question_option');
}
}
Your models will need to recognize this new Pivot Model with the method using(). Here is an example with Survey Model
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Survey extends Model
{
/**
* The users that belong to the role.
*/
public function questions()
{
return $this
->belongsToMany(Question::class)
->using(SurveyQuestion::class);
}
}
And them you will be able to access via eloquent like this
$survey->questions->pivot->options
For more information you can check the documentation here:
https://laravel.com/docs/8.x/eloquent-relationships#defining-custom-intermediate-table-models

How can I fetch value from 3 tables using laravel relationship?

I have 4 tables named: categories, products, blogs, companies.
+-----------+
| Category |
+----+------+
| id | name |
+----+------+
| 1 | Cat1 |
| 2 | Cat2 |
+----+------+
+-----------+
| Company |
+----+------+
| id | name |
+----+------+
| | |
+----+------+
+-------------------------+
| Product |
+----+-------------+------+
| id | category_id | name |
+----+-------------+------+
| 1 | 1 | P1 |
| 2 | 2 | P2 |
| 3 | 1 | P3 |
+----+-------------+------+
+---------------------------+
| Blog |
+----+------------+---------+
| id | product_id | heading |
+----+------------+---------+
| 1 | 1 | H1 |
| 2 | 2 | H3 |
| 3 | 3 | H4 |
+----+------------+---------+
Blog Model
public function product()
{
return $this->belongsTo(Product::class);
}
Product Model
public function company()
{
return $this->belongsTo(Company::class);
}
public function category()
{
return $this->belongsTo(Category::class);
}
Blog::with('product.category')
->where('status', 'Y')
->where('featured_position', 'Y')
->orderBy('id', 'DESC')
->get();
From the above tables the result will show 2 blogs namely blogs having id 1 and 3. But the above code is fetching result for all the blogs from the blog table.
You'll want to use a whereHas to query the relationship.
$categoryId = 1;
$productQuery = function ($query) use ($categoryId) {
// This $query object will be for the Product models, so we can treat it as
// such.
// We can query like we would on a Product, like Product::where([...]).
$query->with('category')->where('category_id', $categoryId);
};
$blogs = Blog::whereHas('product', $productQuery)
->with(['product' => $productQuery])
->get();
I've set the category ID to a variable, in case you need to change it during runtime.
Also, note that the with is completely optional.
If you exclude it, your query will run exactly the same, just without constrained eager loading. The effects of this are just that you will have to perform more database requests. The benefits come if you never actually need the relationship, then it won't have been fetch unnecessarily.
If you're curious what the SQL command will be, it will be:
SELECT * FROM `blogs`
WHERE EXISTS (
SELECT * FROM `products`
WHERE `blogs`.`product_id` = `products`.`id` AND `category_id` = ?
)
In simple terms, it will select everything from the blogs table.
It's then going to query the products table, using an inner join, to select products that have a corresponding blog entry.
The second part of the where clause is going to just get the specific character. The ? is because category_id can be any integer.
Catory with id 1
fetch its products
fetch blogs for each of its products ( map over products )
flatten the results ( since its gonna be nested for each product )
Category::find(1)->products->map->blogs->flatten();
you can use Tinker to interact with you application's query builder and eloquent models from terminal you can use :
$ php artisan tinker
For more clause you can use collection methods :
Category::find(1)->products->map->blogs->flatten()->where('status', 'Y')
->where('featured_position', 'Y')
->sortDesc('id') ;

Codeigniter 3 Joins in One table

I want to display the User Name Who created, but in the database the create name is in the form of int which is the id of the author.
How can I display the id to be the real name by using Join in one table.
Or if there is another way I will try.
For the table as below
+----+--------------+-------------+
| Id | user_create | name |
+----+--------------+-------------+
| 1 | Null | Admin |
| 2 | 1 | User |
+----+--------------+-------------+
and I want to display it like this
Detail User
Name : User
User Create : Admin
if I remember correctly the CI 3 syntax
$this->db
->select(['t1.name', 't2.name user_create'])
->join('thetable t2', 't2.user_create = t1.id', 'left')
->get('thetable t1');

Connect a table to many to many table

I have a many to many table from goods and companies and i want to connect it with a one to many table
company_good
+----------------+------------+
| company_ID | good_ID |
+----------------+------------+
| 1 | 1 |
| 2 | 1 |
| 2 | 2 |
+----------------+------------+
sales
+----------+----------------+--------------+----------+
| id | date | company_id | good_id |
+----------+----------------+--------------+----------+
| 1 | 2019-02-01 | 1 | 1 |
| 2 | 2019-02-01 | 2 | 1 |
| 2 | 2019-02-01 | 1 | 1 |
+----------+----------------+--------------+----------+
what i want to ask is are there any naming column on sales based on laravel rule? what i know is when a table posts want to connect it to table users the naming on table post should be user_id. but in this case how do i name it?
First off, you'll definitely want to use Eloquent for this.
The column names can be whatever you want them to be. When you set up a many to many model method you can define the related column names in there
Here's an extract from the Laravel documentation:
In addition to customizing the name of the joining table, you may also
customize the column names of the keys on the table by passing
additional arguments to the belongsToMany method. The third argument
is the foreign key name of the model on which you are defining the
relationship, while the fourth argument is the foreign key name of the
model that you are joining to:
return $this->belongsToMany('App\Role', 'role_user', 'user_id',
'role_id');
Read more at https://laravel.com/docs/5.8/eloquent-relationships#many-to-many
I suggest to add an id column to company_good table and name corresponding model as CompanyGood and instead of company_id and good_id in sales table use company_good_id column

Laravel. How to get relationships where foreign key is an array

I am trying to retrieve database rows with their relationships. However, the local key is an array. Let me explain using an example.
Lets say I have a table of countries and a table of pages. Each country can have many pages. Each page can belong to multiple countries. I do not have the flexibility to change this schema.
pages
+-------------+-----------+
| id | name | countries |
+-------------+-----------+
| 1 | Page 1 | 1 |
+-------------+-----------+
| 2 | Page 2 | 1,2,3 |
+-------------+-----------+
| 3 | Page 3 | 4,5,6 |
+-------------+-----------+
countries
+----+----------------+
| id | name |
+----+----------------+
| 1 | United States |
+----+----------------+
| 2 | United Kingdom |
+----+----------------+
| 3 | Germany |
+----+----------------+
| 4 | France |
+----+----------------+
| 5 | Hong Kong |
+----+----------------+
| 6 | Thailand |
+----+----------------+
| 7 | Belgium |
+----+----------------+
| 8 | Singapore |
+----+----------------+
My model and controller look something like:
country
public function pages()
{
return $this->hasMany(Page::class, 'id', 'countries');
}
MemberController.php
$countries = Country::with('pages')->get();
This is returning all countries, but only Page 1 contains any relationships.
Is there a way to retrieve relationships using a whereIn approach so all three countries will return appropriate pages?
Thanks in advance
Since Page can belong to many Countries, you need to create a pivot table called country_page and remove the countries column.
Then define two belongsToMany() relationships in both models:
public function pages()
{
return $this->belongsToMany(Page::class);
}
If you're not following Laravel naming conventions listed in my repo and you gave the pivot name a custom name, define it too:
public function pages()
{
return $this->belongsToMany(Page::class, 'custom_pivot_table');
}
Something like this ?
$datas = Pages::where( ##your conditions### )->get()->inArray();
$countries = Countries::pluck('name','id'); // return array of id=>name
foreach($datas as $key=>$data) {
$c = [];
foreach(explode(',',$data['countries']) as $country_id) {
$c[]=$countries[$country_id];
//or
$c[]= ['id'=>$country_id,'name'=>$countries[$country_id]];
}
$datas[$key]['countries']= $c;
}

Resources