Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

Charrua's avatar

Trying to get related models between date ranges, need advice on architecture

Hello, I'm struggling with obtaining some related models on custom date ranges. This is a school app that manages members and attendances. Each Member has many Attendance, when the member comes to school, a new record on the attendance table is inserted.

I would like to get some inactivity information to send some emails, for example:

-members who are inactive one week

-members who are inactive two weeks

-members who are inactive one month

-members who are inactive two months

The problem is that those members that are inactive for example one month, are also inactive one week, so if I send an email to inactive members from one week, also other inactive members are going to get this email.

I can get those ranges mentioned earlier, for example:

//Member.php
public function oneWeekInactive(){
    $date = new Carbon;
    $start = $date->copy()->subDays(8);
    $end = $date->copy();
    return $this->hasMany('App\Attendance')->whereBetween('scan_date', array($start, $end));
}

In my controller the query for those members is:

$members_to_notify = \App\Member::withoutGlobalScope(SchoolScope::class)
    ->whereNotNull('email')
    ->doesntHave('oneWeekInactive')
    ->get();

So my first question is, do you think I need to redefine those ranges as:

-members who are inactive ONLY one week

-members who are inactive ONLY two weeks

-members who are inactive ONLY one month

-members who are inactive ONLY two months

If the redefine is correct, how do you think I can get members for the first range get members with more than one week inactive but not two week inactive I know I need to subtract those members in some way but I'm stuck.

0 likes
4 replies
ftiersch's avatar
ftiersch
Best Answer
Level 28
public function scopeOneWeekInactive($query) {
    $query->whereDoesntHave('attendances', function ($query) {
        $query->where('scan_date', '>', now()->subDays(8));
    })
    ->whereHas('attendances', function ($query) {
        $query->where('scan_date', '>', now()->subDays(15));
    });
}

Now you can use this to get all members that have been inactive for one - but not two - weeks:

$oneWeekInactive = Member::oneWeekInactive()->get();
1 like
Charrua's avatar

@FTIERSCH - Thank you for your help, this is getting closer, the result of that implementation is getting me the members that have activity between the range

now()->subDays(15) > 'scan_date' > now()->subDays(8)

Remember I need those members that have no activity on that date range

ftiersch's avatar

No, that's the thing. Someone who has activity in that range has been inactive for 1 week but has been active within two weeks :) (although the 8 days should probably be 7 in that case).

So for two weeks you basically want everyone who has NO activity in the last two weeks but DOES have activity in the last month.

That way you don't have your overlap between 1-week-inactive people and 2-week-inactive people.

1 like
Charrua's avatar

@FTIERSCH - You are right, I was thinking in the wrong way. Thank you very much for your help! Solved my issue

Please or to participate in this conversation.