Laravel relational queries - ManytoManytoMany - laravel

In my query I need to couple my Workflow model to the currently logged in Client via two linked tables: ClientCompany and CompanyWorkflow.
Getting the base-query written down wasn't a problem:
DB::table('workflows AS w')
->leftJoin('company_workflow AS cw', 'cw.workflow_id', '=', 'w.id')
->leftJoin('client_company AS cc', 'cw.company_id', '=', 'cc.company_id')
->where([
['cc.client_id', '=', $this->id]
]);
This query won't be accepted as a relational query and I would like to use the following method $client->workflows to get the available set of workflows.
Is there a way I can either convert a query to a relational query or a way in which I can chain multiple belongsToMany queries?
My database structure is as such:
client
id
client_company
id client_id company_id
company
id
company_workflow
id company_id workflow_id
workflow
id
UPDATE: Currently I've been able to construct the following hasManyThrough which almost outputs the correct query:
$this->hasManyThrough('\App\Workflow', '\App\CompanyWorkflow', 'workflow_id', 'id')
->leftJoin('client_company AS cc', 'company_workflow.company_id', '=', 'cc.company_id')
->where([
['cc.client_id', '=', $this->id]
]);
The above query is constructed as:
select * from `workflows` inner join `company_workflow` on `company_workflow`.`id` = `workflows`.`id` left join `client_company` as `cc` on `company_workflow`.`company_id` = `cc`.`company_id` where `company_workflow`.`workflow_id` = ? and (`cc`.`client_id` = ?)
But for some reason, I am still not getting any results. Direct execution in the database with the correct ids however DOES return the correct set.
Will update the question when I've found the answer.

Related

Laravel query use parent column inside whereRelation

I have problem with my eloquent query, i need to use data of my base model into whereRelation.
I tried this query bottom, but results was not what i except. The query return me all users who have one city relation, not only user who have city updated between my last user sync.
$users = People::whereRaw('TIMESTAMPDIFF(SECOND, people.latest_sync, people.updated_at) > 20')
->orWhereRelation('city', 'updated_at', '>', 'people.updated_at')
->get();
I'v tried people.updated_at and latest_sync in value of my Where Relation
Do i need to make pure SQL Raw query with classic join ?
PS: the first whereRaw is ok, and work (i really need)

Laravel - Get records between two dates from second table

I have something like this:
Table 1: Training Name, created_at, user_id (Plan_Treninga)
Table 2: user_id, created_at, expire_at (InvoiceUser)
I want to pull all from Table 1 where created_at is between Table 2 created_at and expire_at.
This is something what i am trying to..
$plan = Plan_Treninga::whereBetween(function($q) use ($id){
$inv = InvoiceUser::where([
["user_id",$id],
["status","paid"],
])->latest("id")->first();
})
I haven't finished it yet, but my brain stopped working so I have to ask here.
If I understand what you want clearly is. you want to query all from table 1 which created exist between table 2 created and expire_at right? if so you can use where exist query to achieve this.
// assume your table name is plan_treningas & invoice_users
Plan_Treninga::whereExists(function ($query) {
$query->select(DB::raw(1))
->from('invoice_users')
->whereRaw('plan_treningas.created_at BETWEEN invoice_users.created_at AND invoice_users.expire_at'); // add more query depend your logic
})->get();
for more you can take a look at docs
or if you want to use raw query
SELECT
*
FROM plan_treningas
WHERE EXISTS (
SELECT 1 FROM invoice_users WHERE plan_treningas.created_at BETWEEN invoice_users.created_at AND invoice_users.expire_at
)
Take a look at joins https://laravel.com/docs/7.x/queries#joins
I am not saying this is the exact solution but I have something similar that I have changed to point you in the right direction.
With joins you can do lots of things.
$results = DB::table('table1')
->join('table2', function ($join) {
$join->on('table1.user_id', '=', 'table2.user_id')
->where('table2.status', '=', 'paid')
->where('table2.created_at', '>', 'table1.created_at');
})
->get();
Also look at relationships. There is some good answers for setting up many to many relationships.
https://laravel.com/docs/7.x/eloquent-relationships#many-to-many

Laravel eloquent query with nested whereDate

I currently have a table called operators
The columns are:
id, user_id, item_clicked, created_at, updated_at
I can confirm on one of these it has today's update_at
2019-08-05 showing as today.
This is a relational table.
operators belongs to users.
I'm attempting to get operators of users whereDate is today.
My code is:
$ordersClicked = User::with('operators')
->whereDate('updated_at', \Carbon\Carbon::today())
->get();
This returns an empty array.
Testing this works so I know the data I need is there.
$ordersClicked = User::with('operators')
->get();
$operator = Operator::whereDate('updated_at', \Carbon\Carbon::today())->get();
Any idea what I'm doing wrong?
According to the docs https://carbon.nesbot.com/docs/ Carbon::today() returns Y-m-d H:i:s, if used like you are doing in a where clause and the database stores the value in Y-m-d format.
Why don't you try this:
$ordersClicked = User::with('operators')
->whereDate('updated_at', \Carbon\Carbon::today()->format('Y-m-d'))
->get();
if that doesn't work; then it is possible the eloquent is applying the where clause on updated_at on the User table, instead of Operator. Did you mean to do something like this:
$ordersClicked = User::with(['operators' => function($query) {
$query->where('updated_at', \Carbon\Carbon::today()->format('Y-m-d'))
}])->get();
i.e. filter on the eager loaded collection? if this is what you intended, what will happen is it will return all users and only some operators that has the updated_at matching the criteria will have values, where others will be null.
Wouldn't it be better to reverse the query? i.e. make sure Operator has a belongsTo relationship on User model and query the data like this:
$operator = Operator::whereDate('updated_at', \Carbon\Carbon::today())
->with('user')
->get();

Lean Eloquent Results ->with() Eager Loading

I have a query I am working on that feeds into a javascript engine where there is a lot of information returned that isn't used in the javascript. The results are over 1MB and some of that is because of some eager loading. Here is the query:
$customers = Customer::where('customers.office_id', $officeid)
->where("customers.parent_id", null)
->with('lastAppointment')
->with('nextAppointment')
->select("customers.id","customers.family_id", "customers.gender", "customers.family_size", "family_value")
->get();
The relationship of lastAppointment creates a returned nested object with all the columns from the appointments table, where I really only want a single column of start_at
If I do a ->leftJoin() I can limit my results using the final select like this:
->leftJoin(DB::raw("(select customer_id, MAX(start_at) as lastAppointment from appointments group by customer_id) as appt"), 'customers.id', '=', 'appt.customer_id')
->select("customers.id","customers.family_id", "customers.gender", "customers.family_size", "family_value", "appt.lastAppointment")
I am just wondering if there is a way of doing something similar using ->with()?
You can use this code
->with('lastAppointment:_relation_id,start_at')
where _relation_id is customer_id or primary key of lastAppointment correspond model: depends on your table relation. See docs part of Nested Eager Loading
https://laravel.com/docs/5.5/eloquent-relationships#eager-loading p
The with function will accept a callback as the array value of the relationship key. You then have access to the underlaying query builder instance, I think this is what you want:
->with(['lastAppointment' => function($query) {
return $query->latest()->select('customer_id', 'start_at')
->groupBy('customer_id');
}])

Laravel Eloquent orWherePivot Not Returning Expected Result

I have an eloquent query where I am not getting the expected results and I was hoping someone could explain to me what the correct way to write the query.
I have three tables:
records (belongsToMany users)
users (belongsToMany records)
record_user (pivot)
The record_user table also has a column for role.
I attempt to get all the records where the user has the role of either singer or songwriter:
$results = User::find(Auth::user()->id)
->records()
->wherePivot('role', 'singer')
->orWherePivot('role', 'songwriter')
->get();
Below is how the SQL syntax is generated:
select `records`.*, `record_user`.`user_id` as `pivot_user_id`,
`record_user`.`record_id` as `pivot_record_id` from `records`
inner join `record_user` on `records`.`id` = `record_user`.`property_id`
where
`record_user`.`user_id` = '1' and `record_user`.`role` = 'singer' or
`record_user`.`role` = 'songwriter'
The results for singer role are what is expected: All records where the user is the singer. The problem is the results for the songwriter: I am getting ALL songwriters and the query is not constrained by the user_id. For some reason I was expecting the songwriter role to also be constrained by the user_id - what is the correct way to write this using the eloquent syntax?
Hmm..I think you need to use an advanced where clause.
$results = Auth::user()
->records()
->where(function($query) {
$query->where('record_user.role', '=', 'singer')
->orWhere('record_user.role', '=', 'songwriter');
})
->get();
It is Laravel issue. In my case I solve it like this:
$results = Auth::user()
->records()
->wherePivot('role', 'singer')
->orWherePivot('role', 'songwriter')
->where('user_id', Auth::id())
->get();
Or use advance where clause
If your trying to get records I would do something similar to this:
User::find(Auth::user()->id)
->records()
->where(function($q){
$q->where('records.role', 'singer')
->orWhere('records.role', 'songwriter');
})->get();

Resources