Chaining many to many pivot table query Laravel - php

In my application I have a search filter for Jobs (Model Job) which have a many to many relation with Services (Model Service). Apart from this Jobs have other characteristics as well presented as columns inside the jobs table as status for example.
So what I am doing is I have a multiple input form which data after submit I transform to query my database.
What I am doing is:
$job = new Job();
and then start my query with
$job->newQuery();
and start chaining wheres depending on the data from the form like
$job->newQuery()->where('status', 2);
etc.
My problem comes when the time to chain the services as a where clause. In the form the services is represented as a multiple select box so the data available to me to chain in a where clause is an array like [1,2,5] which represent the ids of the services the jobs I am looking for include but I do not know how to do this in Laravel.
I do have a pivot table job_service which has job_id and service_id etc. Any help would be appreciated thanks in advance.
What I have until now in the case I am searching for jobs that have the services [1,3,6] is something like
App\Job::where('status', '=', 2)
->whereHas('services', function($q) {
$q->whereIn('service_id',[1,3,6]);
}, '=',3)->get();
But the above returns results which have more than 3 services as well:(

Related

Laravel select from DB where in Collection - Laravel Nova

I have a DB, "views," with many, many entries. I also have a "Courses" table, which these views are one-many related to. In Laravel Nova, I can get a metric of all views over time for a course with some code like this:
public function calculate(Request $request)
{
return $this->countByDays($request, view::where('viewable_id', $request->resourceId));
}
In this case, viewable_id is the id of the course, and $request->resourceId gives the ID of the course to sort by. Pretty simple.
However, now things get a little difficult. I have another model called Teachers. Each Teacher can have many courses, also in a one-many relationship. How do I get a metric of views over time for all the courses that teacher teaches?
I assumed the simplest way to do this would be to create a Laravel Collection with all courses the Teacher teaches (not exactly efficient), and then select all views in the database where viewable_id matches one of the courses in that list. Of course, by posting this, I couldn't figure out how to do that.
Of course, once this is figured out, I'd love to do the same thing for Categories (though that should function in a very identical manner to Teachers, so I don't need to ask that question).
How do I get a metric of views over time for all the courses that teacher teaches?
This should be the "countByDays" of views where the viewable_id is in the list of course ids that the teacher teaches.
An SQL query statement to achieve that is given below:
select * from "views"
where "viewable_id" in (select "id" from "courses" where "teacher_id" = ?)
The Eloquent query should be similar to:
$this->countByDays($request,
view::whereIn(
'viewable_id',
Course::with('teacher')
->select('id')
->where('teacher_id', $request->resourceId)
)
);

Laravel 5.1 / Eloquent: How do I use a 3rd table to select from the second table

I have three tables: users, purchase_orders and approvals.
One purchase_order has to be approved by multiple users.
When a new purchase_order gets created, I also create 3 pending approvals belonging to that PO.
The approvals table has a field allowed_user_type that determines who can approve it.
I can't figure out, what is the Eloquent way of selecting the pending purchase orders that can be approved by a specific user, as these are determined from the approvals table.
So far I can pull the pending approvals from the approvals table for a user with the following in the User model.
public function approvals_pending()
{
return $this->hasMany('App\Approval', 'allowed_user_type', 'user_type')
->where('approved', '=', 0);
}
The question is, how do I combine this with a theoretical filter?
I mean ideally, I would love to write:
return $this->hasMany('App\PO')->whereIn('id', '=', $this->approvals_pending()->get()->po_id);
Or something like that...
Any ideas would be greatly appreciated.
OK, for anyone interested I found a solution:
It's very close to what I thought I would have to write.
The lists method basically creates a single array out of the selected field, so it can be plugged-in directly to a whereIn method like so:
return \App\PO::whereIn('id', $this->approvals_pending()->lists('po_id'));
I don't know if this is the most Eloquent way of doing this but it does work.

In Laravel Eloquent, select "whereIn" from parent table

In my Laravel project (with MySQL database), I have a few models: Time Entries, Tasks, and Projects.
Time Entries belong to Tasks
Tasks belong to Projects
so each table contains a column for the corresponding ID of its parent.
I have an array of Project IDs, and I am trying to select the time entries which, through their tasks, belong to those projects.
In other words, I'd like to be able to do something like this:
$timeEntries = TimeEntry::whereIn('project_id',$projectIds)->get();
But obviously, I get a column not found error, because all I've got in the time entries table is task_id rather than project_id.
Is there a way to select the desired time entries (based on the project IDs I have) in a single Eloquent query? Help much appreciated.
Add the following method in your Project model
public function timeEntries()
{
return $this->hasManyThrough('App\TimeEntry' , 'App\Task');
}
now you can get all time entries of a project like below
$project = Project::find(id);
$project->timeEntries()->get();
So the type of relation you're explaining is a through relation (http://laravel.com/docs/5.1/eloquent-relationships#has-many-through).
Instead of trying to head up the tree head down the tree from projects->tasks->time_entries.
Projects::whereIn($projectIds)->with('time_entries')->get();
The resulting collection will be projects with (should be at least) a field called time_entries in each project that have all the relevant times.

Sorting collection via nested relationships

Ok so I have an app that searches through course applications which each belong to an applicant. When I search the applications for a course title it returns the required result set but I would like to sort it by the applicant's date of birth.
How can I do this? I've tried sorting the collection doing $applications->sortBy('applicant.dob') but this seems to just order it by each applicant not the overall collection.
Edit
Here's all of my code... http://laravel.io/bin/PD81z
Any one have an idea how I can approach this?
Thanks!
OK
Your table course and table applicant are actually many-to-many relationship
For this to work, table course_applitions serves as a proxy to link the two table.
see the post, especially the part about many-to-many relationships
http://scotch.io/tutorials/php/a-guide-to-using-eloquent-orm-in-laravel
When fetching results from related tables using the above way, you can always add sort options.
Cheers!

CakePHP Pagination with conditions on has_many

So I have a User table and a History table with User hasMany Histories, and I'm trying to implement pagination on the user table.
My problem is that I have search, and some of the things one can search by are things in the History table. Is there a way to filter pagination results based on data in a table associated by hasMany? Containable, which initially seemed like a solution, allows such filtering but only in the retrieval of associated data, not the records themselves (unless I'm missing something?)
Has anyone had to solve this before?
Since it's a hasMany relationship, that means Cake will need to make 2 separate queries: 1 on the users table, and one on the histories table to retrieve all the associations. Since the History data isn't being retrieved until the 2nd query, then your 1st query cannot be filtered via WHERE conditions for fields found in the History model.
To resolve this, you can do one of two things:
Perform pagination on History using Containable (since History belongsTo User, meaning only 1 query will be performed).
Perform pagination on User the way you're already doing, except perform an ad-hoc join to History such that it's no longer a hasMany relationship.
e.g.:
$this->User->bindModel(array('hasOne' => array('History')));
$this->paginate['User']['contain'][] = 'History';
$this->paginate('User', array('History.some_field' => 'some_value'));

Categories