Laravel Eloquent - Ordering by specific ID of the child - php

I have 3 models: Schedule, Shift, and User. A Schedule has many Shift, and each Shift belongs to a Schedule and has one User.
To get my schedule (with shifts and user), I use:
Schedule::with(['shifts', 'shifts.user'])->find($id);
I want to order this schedule by a specific user id - i.e. if you are looking at a schedule, I want your shift to be the first one on the schedule.
All I could find online was how to order the parent Eloquent model (i.e. Schedule here) using orderByRaw()
User::orderByRaw(DB::raw("FIELD(id, $user_id)"));
I tried to put this in the $query of the with statement, but this didn't work:
Schedule::with(
[
'shifts',
'shifts.user' => function($query) use ($user_id)
{
$query->orderByRaw(DB::raw("FIELD(id, $user_id)"));
}
])->find($id);
Any ideas?

Related

Laravel hasActiveOneOfMany relation

Obviously this does not exist but I am looking for a way to implement it.
Example, I am playing a game where I have 3 teams but I can only be actively playing for one team at any time and when I switch team I essentially starting from the beginning but I would like to retain the progress if I switch team.
My tables would look something like this:
Users:
active_team_id
TeamProgress:
user_id
team_id
team_level
team_xp
TeamNames:
id
team_name
So there would only be 3 teams defined in TeamNames and while any one of these 3 are active (as set in active_team_id in the users table) then I want to be able to directly target it with something like
$user->teamProgress->update()
and update the active team directly.
Similarly I would like to do something like
$user->teamProgress->get()
and just get the team progress for that users active team while a few others may exist within team progress.
Then if I switch the active_team_id on the user table and do the same calls above I now update / get info for the second team specified in active_team_id
Is there a way to do this with a relation or am I overthinking this and better off doing this by just directly targeting the TeamProgress model using the information I already have as a user?
$teamProgress->where('user_id', $user->id)->where('team_id', $user->active_team_id)->get()
You can try this package https://github.com/topclaudy/compoships. It allows you to define relations by matching multiple columns. For example
class User extends Model
{
use \Awobaz\Compoships\Compoships;
public function activeTeamProgress()
{
return $this->hasOne(TeamProgress::class, ['id', 'active_team_id'], ['user_id', 'team_id']);
}
}

Laravel Eloquent / Carbon between two dates

Some background first, I have a contact model to keep track of a user's contacts, and I have an anniversary model, they are linked as Many-to-Many with a pivot table (Each user can decide his/her own anniversaries and then add those to a contact, so the anniversaries are not hard coded).
So each User hasMany Anniversaries and every Contact can have many Anniversaries, while an Anniversary can have many Contacts.
For example, to get upcoming birthdays for all contacts for the next x months, I use the following query:
auth()->user()->contacts()->whereBetween(DB::raw('DATE_FORMAT(birthdate, "%m-%d")'), array(
Carbon::now()->format('m-d'),
Carbon::now()->addMonths($months)->format('m-d')))
->get();
This works perfectly. However, for the anniversaries it is a bit more complicated. An anniversary at this moment can have a frequency of monthly, quarterly, semi-annually and annually. This is stored as a string in the pivot table anniversary_contact.
I would like to use a similar query for this as the above one, but I am wondering if this is at all possible without having to repeat a lot of orWhereBetween like below:
In the below query I check for upcoming anniversaries with a frequency of monthly for the next 3 days:
$anniversaries = auth()->user()->contacts()->get()->each(function ($contact)
{
$contact->anniversaries->each(function ($anniversary) {
return $anniversary->whereBetween(DB::raw('DATE_FORMAT(date, "%m-%d")'), array(
Carbon::now()->format('m-d'),
Carbon::now()->addDays(3)->format('m-d')))
->orWhereBetween(DB::raw('DATE_FORMAT(date, "%m-%d")'), array(
Carbon::now()->addMonths(1)->format('m-d'),
Carbon::now()->addDays(3)->format('m-d')))
->get();
// Left the rest of the 10 "orWhereBetween" out of it in this example
});
});
Although the above repetition is a seperate issue, my main issue is this:
DB::raw('DATE_FORMAT(date, "%m-%d")')
There is no date field in the anniversaries table, it is in the pivot table.
Main question: How to use the above query to get the results I need, from checking against the pivot date?
Bonus question: Can the above query be made "simpler" or "smaller" without having to use a lot of orWhereBetween statements? If I need to check an upcoming anniversary that is a monthly one, I will have 12 orWhereBetween statements. Can this be reduced?
Or should I forget about checking it on the database level and instead get all anniversaries and use Carbon to check against upcoming anniversaries?

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.

Categories