As far as logic goes, you want this:
- The Start Date of the Event happened before
To- i.e. The Start Date needs to be in the past from the perspective of
To
- i.e. The Start Date needs to be in the past from the perspective of
-
AND The End Date of the Event happened after
From- i.e. The End Date needs to be in the future from the perspective of
From
- i.e. The End Date needs to be in the future from the perspective of
In this example, your query would be:
$user = User::where('id', Auth::user()->id)
->with([ 'events' => function($query) use ($from, $to) {
$query->where('start', '<=', $to)->where('end', '>=', $from)
}])
->first();
To clean things up a bit, I like to add "Time" Macros to all of my Queries:
AppServiceProvider:
use Carbon\Carbon;
use Illuminate\Database\Query\Builder;
public function boot()
{
Builder::macro('past', function($column, $when = 'now', $strict = true) {
$when = Carbon::parse($when);
$operator = $strict ? '<' : '<=';
return $this->where($column, $operator, $when);
}
Builder::macro('future', function($column, $when = 'now', $strict = true) {
$when = Carbon::parse($when);
$operator = $strict ? '>' : '>=';
return $this->where($column, $operator, $when);
}
}
This would allow you to make queries like this:
$user = User::where('id', Auth::user()->id)
->with([ 'events' => function($query) use ($from, $to) {
$query->past('start', $to)->future('end', $from)
}])
->first();
To take things a step further, I'd add this as a scope to your Event Model:
public function scopeOverlapping($query, $from, $to)
{
return $query->past('start', $to)->future('end', $from);
}
Which further clarifies your original query to:
$user = User::where('id', Auth::user()->id)
->with([ 'events' => function($query) use ($from, $to) {
$query->overlapping($from, $to);
}])
->first();
Now then, a few optimizations:
Judging the context of this query, you're wanting to load the overlapping events onto the Authenticated User. Seeing as you already have the Model, it might make more sense to do this:
$events = Auth::user()->events()->overlapping($from, $to)->get();
If you really need the Authenticated User to be passed along with an $events variable, you can always do this:
$user = Auth::user()->setRelation('events', $events);
This could be inlined as:
$user = Auth::user()->setRelation('events',
Auth::user()->events()->overlapping($from, $to)->get()
);
This effectively does exactly the same thing, but I consider it to be more readable than a ->with construct using an array and a closure.
To clean things up even further, you could add the following function to your User Model:
public function loadOverlappingEvents($from, $to)
{
return $this->setRelation('events',
$this->events()->overlapping($from, $to)->get()
);
}
Seeing as the setRelation function returns the calling Model, you could now do this:
$user = Auth::user()->loadOverlappingEvents($from, $to);
$events = $user->events;
I know that I probably said more than what you needed, I just wanted to point out some design tips. Hopefully somewhere along writing all of this, I managed to answer your question.