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

yagrasdemonde's avatar

Constraining relationships problem !

Hello all,

I have a problem with my query and to be honnest, I don't understand what is wrong !

So this is the situation : I have a form for a user to subscribe one of selection session. He can choose a date with datepicker input. When date is chosen, ajax call is executed to show sessions related to this date (called eventDate).

So the query have to select sessions with one or many steps inside, but ONLY sessions where steps are including between eventDate and eventDate -4 months. It is therefore necessary to check that the steps of each session are included between eventDate-4mois and eventDate, so as to return only the corresponding sessions in the form

I try this query, but it doesn't work as expected.

return Session::
            with('steps')
            ->whereHas('steps', function ($query) use ($eventDate) {
                $query
                    ->whereDate('date', '>=', $eventDate->copy()->subMonths(4)->format('Y-m-d'))
                    ->where('date', '<=', $eventDate->format('Y-m-d'));
            })
            ->get();

For informations, I declare

//Session model
class Session extends Model
{
	public function steps()
    {
        return $this->hasMany(Step::class);
    }
}
//Step model
class Step extends Model
{
	protected $dates = [
        'date'
    ];

	public function session()
    {
        return $this->belongsTo(Session::class);
    }
}
sessions table
| id (int) | title (varchar)               |
|----------|-------------------------------|
| 13       | SessionTest                   |
| 14       | Session Two                   |
| 25       | Session 4                     |
| 27       | Session from 14 nov to 21 nov |
| 28       | Session from 23 jan to 13 feb |
steps table

| id (int) | title (varchar) | date (datetime)     | session_id (int) |
|----------|-----------------|---------------------|----------------|
| 1        | Step 1          | 2020-04-20 10:00:00 | 13             |
| 2        | Step 2          | 2020-10-17 15:00:00 | 13             |
| 3        | Step 3          | 2020-11-27 10:00:00 | 13             |
| 4        | Step A          | 2020-12-25 10:00:00 | 14             |
| 5        | Step B          | 2021-01-09 14:00:00 | 14             |
| 6        | 1 Step          | 2020-06-06 10:00:00 | 25             |
| 7        | 2 Step          | 2020-06-20 12:40:00 | 25             |
| 8        | 3 Step          | 2020-06-27 12:40:00 | 25             |
| 9        | Step AA         | 2020-11-14 12:40:00 | 27             |
| 10       | Step BB         | 2020-11-21 12:40:00 | 27             |
| 11       | Step A1         | 2021-01-23 12:40:00 | 28             |
| 12       | Step A2         | 2021-02-13 12:40:00 | 28             |
subscriptions table
| id (int) | session_id (int) | name (varchar) | eventDate (datetime) |
|----------|------------------|----------------|----------------------|
|          |                  |                |                      |

For example, if I choose 2021-01-30 in my datepiker, my query returns : SessionTest (with relationships : Step 1/Step 2/Step 3) Session Two (with relationships : Step A/Step B) Session from 14 nov to 21 nov (with relationships : Step AA/Step BB) Session from 23 jan to 13 feb (with relationships : Step A1/Step A2)

So the last session - Session from 23 jan to 13 feb - should not to be selected because, second step inside is after the chosen date (2021-01-30).

Session 4 (with relationships : 1 Step/2 Step/3 Step) is not selected because all of steps are outside of eventDate -4 months and eventDate, this is correct Can you help me to make my query like as expected ?

Thank you very much

0 likes
4 replies
SilenceBringer's avatar

Hi @yagrasdemonde I think it should be something like:

return Session::
            with('steps')
            ->whereHas('steps', function ($query) use ($eventDate) {
                $query
                    ->whereBetween('date', [$eventDate->subMonths(4)->format('Y-m-d'), $eventDate->format('Y-m-d')]);
            })
            ->get();
yagrasdemonde's avatar

I had already tested with whereBetween before asking my question. Unfortunately, it is the same result

SilenceBringer's avatar
Level 55

@yagrasdemonde ok, try this

return Session::
            with('steps')
            ->whereHas('steps', function ($query) use ($eventDate) {
                $query
                    ->whereBetween('date', [$eventDate->subMonths(4)->format('Y-m-d'), $eventDate->format('Y-m-d')]);
            })
            ->whereDoesntHave('steps', function ($query) use ($eventDate) {
                $query->where('date', '>=', $eventDate);
            })
            ->get();
yagrasdemonde's avatar

It seems to work very well !! Thank you very much.

But can you explain this ->whereDoesntHave because for each Session, the steps relationship exists. Thank you

Please or to participate in this conversation.