Return data from pivot table with whereIn - php

So I have Status class which has pivot table relationship with roles:
public function roles():
{
return $this->belongsToMany(Role::class, 'status_role', 'status_id', 'role_id');
}
This is how Status db table looks:
id title
1 status1
2 status2
3 status3
And then my pivot table which looks like this:
status_id role_id
1 2
2 2
And now I want to write query which returns statuses with role_id=2.
Basically it should return data like this: status1, status2 and not include status3.
What I have tryed:
$statuses = Status::query()
->leftJoin('status_role', function ($join) {
$join->on('statuses.id', '=', 'status_role.status_id')
->whereIn('status_role.role_id',[2]);
})
->get();
But now it returns all statuses (status1, status2, status3) it should be only (status1 and status2). How I need to change it?

This query will return all statuses attached to roles with id 2:
Status::query()->whereHas('roles', function($q){
$q->where('id', 2);
})->get();
It uses the whereHas method that can be useful when you need to query relationships.
It can do a lot more, you should check the documentation on this topic: https://laravel.com/docs/8.x/eloquent-relationships#querying-relationship-existence
Quick note: whereHas is the "Laravel preferred way" of doing what you are trying to achieve.
However, you should be able to also do it with this query, which is closer to your current code:
$statuses = Status::query()
->join('status_role', function ($join) {
$join
->on('statuses.id', '=', 'status_role.status_id')
->where('status_role.role_id',2);
})
->get();
// I replaced the leftJoin by join, which will exclude all results without roles (e.g. status id 3)
// or even simpler:
$statuses = Status::query()
->join('status_role', 'statuses.id', '=', 'status_role.status_id')
->where('status_role.role_id',2)
->get();

Related

Laravel WithSum / WithCount Relationships not bringing results

I am trying to make a query using Laravel eloquent but at the moment I have not had good results.
My query is about the scope of relationships in Laravel. We have two tables:
table 1 : orders
table 2 : products in orders (depends on table 1)
We have a relationship in the model.
public function products()
{
return $this->hasMany(OrderProduct::class);
}
OrderProduct (detail of products in orders) has the following fields:
id
order_id
product_id
qty
line_total
What we are trying to achieve is a query that returns the sum of line_total when the product_id is 139.
We tried the following options without success in the controller:
$orderspaid = Order::with('products')
->where('customer_id', '=', Auth::id())
->where('status', '=', 'completed')
->withSum ('products','line_total')
->where('product_id', '=', '139')
->get();
Error: Column not found: 1054 Unknown column 'product_id'
$orderspaid = Order::withCount(['products as orderproducts' => function($query) {
$query->where('orderproducts.product_id', '=', 139)
->select(DB::raw('sum(line_total)'));
}])->get();
But with no success.
My main question is, it is possible to use sum(line_total) or withSum('products','line_total') to directly sum the amount of money that a particular product_id have?.
Additional Info: Tinker information displaying the relationship between orders and orderproducts.
You can try this one. I don't have those tables ready to test so I could be wrong
So basicly, the method being tried is that products with wanted id will be preloaded, in this case, it's 139. When withSum is called on products table, it will use eagerly products that have been specified beforehand.
$product_id = 139;
$orderspaid = Order::with(['products' => function ($query) use ($product_id) {
$query->where(`products.id`, $product_id);
}])
->where('customer_id', '=', Auth::id())
->where('status', '=', 'completed')
->withSum('products', 'line_total')
->get();
dd($orderspaid);
Tell me if that works for you.

Problem in building relationships query in Laravel

Suppose we have 3 tables , User , Report and Job. In users table we having 2 columns to use, id and job_id, in report table , we have user_id and job_id'.
So I need all users with report detail, whose job_id and user_id matched User table. I want to do it with relationship.
I made that query.
Problem is how to write multiple where clause with report, (where user_id,job_id).
User:: select(*)->with("report")->paginate(10);
Try this
User model define
public function job()
{
return $this->belongsTo(Job::class);
}
Job model define
public function reports()
{
return $this->hasMany(Report::class);
}
Then use
User::select(*)->with("job.reports")->paginate(10);
Maybe you can do it like
User::whereHas('report', function ($q) use ($id, $sample) {
$q->where('id', $id)
->where('sample', $sample);
})->get();
$id are just sample variable you can pass on to closure, while whereHas able to check if there's existing relationship
or something like,
User::WhereHas('report', function ($q) use ($id, $sample) {
$q
->where('id', $id) // this part here your using where on reports table
->where('sample', $sample);
})
->where('id', $user_id); // the part here your using where on users table
->get();

How to get parents data that only has a child data in laravel

I'm trying to get all the data from the parent that only has a child. Please see my code below.
$customers = Customer::with(['items' => function($query){
return $query->where('status', 2);
}])->get();
dd($customers);
But the code above returns all the customer. By the way, I'm using laravel 4.2.
Items Table:
Customer Table:
with() is for eager loading. That basically means, along the main model, Laravel will preload the relationship(s) you specify. This is especially helpful if you have a collection of models and you want to load a relation for all of them. Because with eager loading you run only one additional DB query instead of one for every model in the collection.
has() is to filter the selecting model based on a relationship. So it acts very similarly to a normal WHERE condition. If you just use has('relation') that means you only want to get the models that have at least one related model in this relation.
e.g :
$users = Customer::has('items')->get();
// only Customer that have at least one item are contained in the collection
whereHas() works basically the same as has() but allows you to specify additional filters for the related model to check.
e.g
$users = Customer::whereHas('items', function($q){
$q->where('status', 2);
})->get();
// only customer that have item status 2
Adding group by to calculating sum
this is another example from my code :
Customer::select(['customer.name', DB::raw('sum(sale.amount_to_pay) AS total_amount'), 'customer.id'])
->where('customer.store_id', User::storeId())
->join('sale', 'sale.customer_id', '=', 'customer.id')
->groupBy('customer.id', 'customer.name')
->orderBy('total_amount', 'desc')
->take($i)
->get()
in your case :
Customer::select(['customer_id', DB::raw('sum(quantity) AS total')])
->whereHas('items', function ($q) {
$q->where('status', 2);
})
->groupBy('customer_id')
->get();
whereHas() allow you to filter data or query for the related model in your case
those customer that have items and it status is 2
afetr getting data we are perform ->groupBy('customer_id')
The GROUP BY statement is often used with aggregate functions (COUNT, MAX, MIN, SUM, AVG) to group the result-set by one or more columns.
select(['customer_id', DB::raw('sum(quantity) AS total')]) this will select customer id and calculate the sum of quantity column
You should use whereHas not with to check child existence.
$customers = Customer::whereHas('items', function($query){
return $query->where('status', 2);
})->get();
dd($customers);
I assume you already defined proper relationship between Customer and Item.
You should try this:
$customers = Customer::whereHas('items', function($query){
$query->where('status', 2);
})->get();
dd($customers);
Customer::select(['items.customer_id',DB::raw('count(items.id) AS total_qty')])
->join('items', 'items.user_id', '=', 'customer.customer_id')
->groupBy('items.customer_id')
->havingRaw('total_qty > 2')
->get();
OR
$data=DB::select("select `items`.`customer_id`, count(items.id) AS total_qty
from `customers`
inner join `items`
on `items`.`customer_id` = `customers`.`customer_id`
group by `items`.`customer_id` having total_qty >= 2");
correct table name and column name.

Laravel | Search in 2 tables

I'm having a problem with my Search functionnality on my website, I have 2 tables: user and review , In my review table, the owner column is equal to the username column in user table, I want to be able to return in the same result the username of the user table and just below the number of review which I can get with:
Review::where('owner', '=', xxx)->where('invitation_id', '')->count();
The xxx should be equal to the username in the user table
And I have to do this to get the username:
User::where('username', '=', xxx)->first();
What I would like to do (I know this is wrong):
$result = User::where('email','LIKE','%'.$search_key.'%')
->orWhere('username','LIKE','%'.$search_key.'%')
AND
Review::where('username', '=', *$result->username* )
->get();
And I would like to be able to return the search result like this in my result.blade.php:
<h3>Username: {{ user->username }}</h3>
<h3>Username: {{ review->number_review }}</h3>
I checked on the Laravel docs to make a relationship between these 2 tables but can't figure it out, I hope what I said is understandable.
You can use eloquent relationship.
// app/Review.php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Review extends Model
{
public function users()
{
return $this->hasOne('App\User', 'owner', 'username');
}
}
I do not suggest two table relation with username/owner. I suggest to you relation with user primary_id
You can get user info with following code;
Review::where('owner', '=', xxx)->where('invitation_id', '')->with('users')->count();
It getting user info with ->with('users') condition in Review model.
You achieve the required matching criteria by using join and parameter grouping clause
$result = DB::table('users as u')
->join('review as r', 'u.username', '=', 'r.owner')
->where('email','LIKE','%'.$search_key.'%')
->orWhere(function ($query) {
$query->where('u.username','LIKE','%'.$search_key.'%')
->where('r.owner','LIKE','%'.$search_key.'%');
})
->get();
Which will produce where clause as
WHERE u.email LIKE '%somevalue%' OR (r.owner LIKE '%somevalue%' AND u.username LIKE '%somevalue%')
For review count
$result = DB::table('users as u')
->select('u.*',DB::raw("COUNT(*) as review_count"))
->join('review as r', 'u.username', '=', 'r.owner')
->where('u.email','LIKE','%'.$search_key.'%')
->orWhere(function ($query) {
$query->where('u.username','LIKE','%'.$search_key.'%')
->where('r.owner','LIKE','%'.$search_key.'%');
})
->groupBy('u.username')
->get();
You will need to join your user table to the review table.
Something along these lines, might need tweaking.
$result = User::query()
->join('review', 'owner', 'username')
->where('email','LIKE','%'.$search_key.'%')
->orWhere('username','LIKE','%'.$search_key.'%')
->orWhere('username', $result->username)
->orWhere('owner', $result->username)
->get();

laravel belongsToMany Filter

I have three tables as below:
users
id|name|username|password
roles
id|name
users_roles
id|user_id|role_id
These tables communicate via belongsToMany.
I would like to find a way to select all data in “users” table except ones that their user value of "role_id" is 5 in table “users_roles”.
How can I do it?
You should use whereDoesntHave() to select models that don't have a related model meeting certain criteria:
$users = User::whereDoesntHave('roles', function($q){
$q->where('role_id', 5);
})->get();
Use Laravel's Query Builder:
<?php
$users = DB::table('users')
->leftJoin('users_roles', 'user.id', '=', 'users_roles.user_id')
->where('users_roles.role_id', '!=', 5)
->get();
http://laravel.com/docs/4.2/queries
Or using Eloquent directly:
<?php
$users = User::whereHas('users_roles', function($q)
{
$q->where('role_id', '!=', 5);
})->get();
http://laravel.com/docs/4.2/eloquent#querying-relations
<?php
$users = User::whereHas('roles', function($query) {
$query->where('id', '<>', 5);
})
->orHas('roles','<', 1)
->get();
I think the correct answer is:
User::whereHas('roles', function ($query) {
$query->whereId(5)
}, '=', 0)->get();
This code should send a query that checks if the role with id=5 is related to the user or not.
Edit
While I think this should work but the #lukasgeiter answer is preferable.
In the end both methods use the has() to count the related models by using a subquery in the db query where clause but when you use the whereDoesntHave() it specifies the operator < and the count 1 itself.
You can var_dump(DB::getQueryLog()) in App::after()'s callback to see the actual query.

Categories