How can i make inner join in method instead of controller? - laravel-5

I have a two tables orders and product. Relation is One to One. In my order class i created method product
public function product() {
return $this->hasOne('App\Product', 'key_id', 'key_id');
}
Now in controller i want select rows where id is not null that's why i wanna use InnerJoin
Order::where('order_id', 7)
->join('products', 'products.key_id', 'orders.key_id')
->get();
That is fine but i would like get
Order::where('order_id', 7)->get();
and all join move to method like:
public function product() {
return $this->hasOne('App\Product', 'key_id', 'key_id')
->join('products', 'products.key_id', 'orders.key_id')
}
How can i do this ?

You have defined the relations between both the models, so If you fetch order with the following query:
Order::where('order_id', 7)->with('product')->get();
Remove the join line from product function i.e. ->join('products', 'products.key_id', 'orders.key_id')
After doing this, dump and die the $order, there will be an key pair with product and its values.

Related

laravel eloquent with pivot and another table

I have 4 table categories, initiatives, a pivot table for the "Many To Many" relationship category_initiative and initiativegroup table related with initiatives table with initiatives.initiativesgroup_id with one to many relation.
With pure sql I retrive the information I need with:
SELECT categories.id, categories.description, initiatives.id, initiatives.description, initiativegroups.group
FROM categories
LEFT JOIN category_initiative ON categories.id = category_initiative.category_id
LEFT JOIN initiatives ON category_initiative.initiative_id = initiatives.id
LEFT JOIN initiativegroups ON initiatives.initiativegroup_id = initiativegroups.id
WHERE categories.id = '40'
How can I use eloquent model to achieve same results?
Since you have such a specific query touching multiple tables, one possibility is to use query builder. That would preserve the precision of the query, retrieving only the data you specifically need. That would look something like this:
$categories = DB::table('categories')
->select([
'categories.id',
'categories.description',
'initiatives.id',
'initiatives.description',
'initiativegroups.group',
])
->leftJoin('category_initiative', 'categories.id', '=', 'category_initiative.category_id')
->leftJoin('initiatives', 'category_initiative.initiative_id', '=', 'initiatives.id')
->leftJoin('initiativegroups', 'initiatives.initiativegroup_id', '=', 'initiativegroups.id')
->where('categories.id', '=', 40)
->get();
In your models define the relationships:
Category.php model
public function initiatives()
{
return $this->belongsToMany('App\Initiative');
}
Initiative.php model (If has many categories change to belongs to many)
public function category()
{
return $this->belongsTo('App\Category');
}
Then maybe change your initiativegroup -> groups table, and then create a pivot table called group_initiative. Create model for group. Group.php and define the relationship:
public function initiatives()
{
return $this->belongsToMany('App\Initiative');
}
Then you can also add the following relationship definition to the Initiative.php model
public function group()
{
return $this->belongsTo('App\Group');
}
That should get you started.
for the record..
with my original relationship, but changing table name as alex suggest, in my controller:
$inits = Category::with('initiative.group')->find($id_cat);
simple and clean

Laravel Fetching one to Many Relationship

Hello I am learning laravel and I am having an issue retrieving data from my relations.
In my database there are Product and Groups filled with dummy data.
I defined my relationship like this in product model:
public function Group()
{
return $this->hasMany('App\Groups','product_id', 'id');
}
And in my group vice versa with :
public function Product()
{
return $this->belongsTo('App\Product','product_id', 'id');
}
The way I am referencing to my products table is :
$table->foreign('product_id')->references('id')->on('products')->onDelete('cascade');
Now I have column product_id in my database under groups, and it is linked to if from products id it seems.
The groups table contains of its auto incremented id and product_id foreign key column.
While products table has auto incremented id and name column.
The issue is here :
How do I return the products that are not null or have value (of products id) in groups table.
I tried something like this in my filter controller:
public function getProductsWithGroup()
{
$Products = Product::with('groups')->get();
return $Products ;
}
But that is giving me call to undefined relations.
I am not sure how to access belongsTo or hasMany methods and whether I need an extra group_id column in my products table.
You named the relationship wrong. It should be groups & define in lowercase as
public function groups()
{
return $this->hasMany('App\Groups','product_id', 'id');
}
And use ->has() to check existence
public function getProductsWithGroup()
{
$Products = Product::has('groups')->get();
return $Products ;
}
->with() is used to eager load and ->has() is used to check existence & filter.
To get the products don't have any groups,
$Products = Product::doesntHave('groups')->get();
To see other ways to use ->has() check, https://laravel.com/docs/5.7/eloquent-relationships#querying-relationship-existence

Laravel Left join multiple tables and return the original table value

I'm having issues with joining three tables and getting the original table value back.
I have a parent table which is a store that needs to find the brand_id for the products within the store. I can't access the brand_id directly so I need to join, I have to join on to the stores product list then join that onto the product table which holds the brand_id.
$this_return = Store::with('address','setting')
->leftjoin('StoreProducts', function ($join){
$join->on('StoreProducts.store_id', '=', 'stores.id');
})->leftjoin('products', function ($join) {
$join->on('products.id','=','StoreProducts.product_id');
})
->where('products.brand_id', '=', $brandID)
->isActive()
->get();
This is returning a product value, But I wanted it to return all the stores the original table back if the products.brand_id was equal to the $brandID then return the current store and repeat for all stores.
Hope that makes sense
Any help would be great.
I think your relations goes like this:
Stores -> (n*n)StoreProducts -> Products -> (n*1)Brands
which StoreProducts is a joining table between Stores and Products. With this assumption, I would use something like this:
In the Store model,
public function products(){
return $this->belongsToMany(\App\Product::class, "store_products");
}
In the Products model,
public function stores(){
return $this->belongsToMany(\App\Store::class, "store_products");
}
In the StoreProducts model,
public function store(){
return $this->belongsTo(\App\Store::class);
}
public function product(){
return $this->belongsTo(\App\Product::class);
}
This way the relationship is created. Then you can use something like this:
$stores = \App\Store::whereHas("products", function($q) use ($brandId){
return $q->where("brand_id", $brandId);
});
This will give you the stores which the brand exists.

Laravel 5.3 inner join not working properly

I'm having two tables as 'jobs' and 'desired_skills'.
Table structure is as follows.
jobs table
jobs Table
desired_skills table
desired_skils table
where desired_skills.job_id refers to jobs.job id
In controller I have (I am getting $id as an argument from the url, and I can confirm the argument grabs the desired value)
$jobs = DB::table('jobs')->where(function ($query) use ($id) {
$query->Join('desired_skills', 'desired_skills.job_id', '=', 'jobs.job_id')
->where('jobs.employer_id', '=', $id);
->select('*')
})->get();
when I dump and die $jobs it only returns values from jobs table.
but when I run the query
SELECT * FROM jobs INNER JOIN desired_skills ON desired_skills.job_id = jobs.job_id it returns the desired value set.
What am I doing wrong? Any help will be greatly appreciated.
I think it has to do with wrapping your join inside of a where clause. I don't think it's giving you your desired query with that there.
$jobs = DB::table('jobs')
->join('desired_skills', 'desired_skills.job_id', '=', 'jobs.job_id')
->where('jobs.employer_id', '=', $id)
->get();
The query SELECT * FROM jobs INNER JOIN desired_skills ON desired_skills.job_id = jobs.job_id
is not the same has what you are trying to do in the function. In this query there is not
mention of 'employer_id' in the table 'jobs'.
An alternative would be to use eloquent relationships, as refered in a comment.
You need 3 classes in models:
Employer
Job
DesiredSkill
Between Employer and Job -> one-to-many relation (an employer can have multiple jobs).
Between DesiredSkill and Job -> one-to-one relation.
I'm not sure what you are trying to get from the join, but i think that if you implement
the methods that allow the relationships i believe you solve whatever.
class Job extends Model
{
public function employer()
{
return $this->hasOne('App\Job');
}
}
class Employer extends Model
{
public function jobs()
{
return $this->hasMany('App\Employer');
}
public function desiredSkill()
{
return $this->hasOne('App\DesiredSkill');
}
}
class DesiredSkill extends Model
{
public function job()
{
return $this->hasOne('App\DesiredSkill');
}
}
Try this:
$jobs = DB::table('jobs')
->join('desired_skills', 'desired_skills.job_id', '=', 'jobs.job_id')
->select('jobs.*', 'desired_skills.*')
->get();

Self Join in Eloquent - How To Call

I recently asked a question regarding a self join
SO
I got a great answer but I'm not sure how to call it.
I need to do this query:
SELECT t2.title FROM products t1, products t2
WHERE t1.id = $id
AND t2.color_id = t1.color_id AND
t2.id != $id
I now have this on my products model:
public function parent()
{
return $this->belongsTo(self::class, 'color_id');
}
public function children()
{
return $this->hasMany(self::class, 'color_id');
}
But how do I call this?
Product::with('children')->find(1);
The above gets the product with id 1 but also gets children that have a color_id of 1, I need to get children who have a color_id the same as the id as product 1.
eg.
Products
id | title | color_id
1 dvd 2
When I select row 1 it should select all other products with a color_id of 2.
I believe your relations are not the way they're supposed to be. Usually it's one column (foreign key - color_id in your case) having a value of the other one (usually primary key - id in your case).
What you have is basically a value the records share or a "category". So your products are not "children" but rather siblings (have the same parent color).
Since with method is not build as a JOIN statement but as eager loading (separate query) you can do that manually.
Probably the most straight forward way:
$product1 = Product::find(1);
$children = Product::where('id', '<>', $product1->id)->
where('color_id', $product1->color_id)->
get();
You can add select('title') to the second "builder" to get only title but that would not be your model anymore. Or you can use lists('title') to extract only titles if that's what you need.
UPDATE:
If you decide you need the JOIN after all I'd suggest going with raw query builder and leave the Eloquent out of it:
$res = DB::table('products as t1')->
select('t2.title')->
join('products AS t2', 't2.color_id', '=', 't1.color_id')->
where('t1.id', 1)->
where('td2.id', '<>', 't1.id')->
get();
I believe it should build something similar to what you need.
You can try this way:
// Category.php
public function children()
{
return $this->hasMany(Category::class, 'parent_id');
}
public function parent()
{
return $this->belongsTo(Category::class, 'parent_id');
}
// To access
$category->children; // sub-categories collection
$category->parent; // parent instance
based on : https://laracasts.com/discuss/channels/eloquent/self-join-in-eloquent-model?page=1
You might want to do as follow :
$id = 1;
$product = Product::with('children')->whereHas('children', function($q) use ($id)
{
$q->where('color_id', $id);
})->find($id);
See Advanced Join Clauses and adapt from my example here.
It took me a long time to wrap my head around Laravel joins.
This:
$postIds = DB::table('comments as t1')
->select('t1.*')
->leftJoin('comments as t2', function ($join) {
$join->on('t1.postId', '=', 't2.postId')
->on('t1.created_at', '<', 't2.created_at');
})
->where('t2.id', '=', null)
->orderBy('t1.created_at', 'DESC')
->simplePaginate(20)
->pluck('postId');
seems to be the way to get an array of the postIds that would be revealed by this:
SELECT t1.*
FROM comments a
LEFT OUTER JOIN comments b
ON t1.postId = t2.postId
AND t1.created_at < t2.created_at
WHERE t2.id IS NULL
ORDER BY t1.created_at DESC
SELECT subcat.CategoryName as SubCat cat.CategoryName as Category FROM bn_bas_categories cat, bn_bas_categories subcat WHERE cat.CategoryID = subcat.ParentID;

Resources