Laravel query not working when using as scope - php

I'm trying to find records by time interval. In table there are columns like 'date_from' and 'date_to', those are specify starts and ends date of an event.
public function scopeByTimeInterval($query, $dateInterval)
{
$query->where(function ($query) use ($dateInterval) {
[$from, $to] = $dateInterval;
$query->where([
['date_from', '<=', $from],
['date_to', '>=', $to]
]);
$query->orWhere([
['date_from', '>=', $from],
['date_to', '<=', $to]
]);
$query->orWhereBetween('date_from', $dateInterval);
$query->orWhereBetween('date_to', $dateInterval);
});
}
when I use where query directly, there are no problem. I can see all events between those dates. But if I use it as a scope, it returns me every events in given year and month and not the interval..
What might cause kind of behavior ? Or am I missing something ?

As mentioned in the comments, your query is essentially selecting everything. If you're trying to get the events that are happening during the $from and $to dates you could do something like:
public function scopeDateInterval($query, $interval)
{
[$from, $to] = $interval;
$query
->where(function ($query) use ($from, $to) {
$query
->where(function ($query) use ($from) {
$query
->where('date_from', '<=', $from)
->where('date_to', '>=', $from);
})
->orWhere(function ($query) use ($to) {
$query
->where('date_from', '<=', $to)
->where('date_to', '>=', $to);
})
->orWhere(function ($query) use ($from, $to) {
$query
->where('date_from', '>=', $from)
->where('date_to', '<=', $to);
});
});
}
The above is basically saying where the $from or $to is between the start and end dates, or the start and end dates are between the $from and $to.

Think you miss return $query->where...

Related

Using whereIn with orWhere functions in Eloquent query

I am struggling to add a whereIn to a more complex query:
$events = Toolplan::query()
->select('id', 'eventId', 'resourceId', 'title', 'start', 'end')
->where(function ($query) use ($start, $end) {
$query->whereDate('start', '>=', $start)->whereDate('end', '<=', $end);
})
->orWhere(function ($query) use ($start, $end) {
$query->whereDate('start', '<=', $start)->whereDate('end', '>=', $end);
})
->orWhere(function ($query) use ($start, $end) {
$query->whereDate('end', '>=', $start)->whereDate('end', '<=', $end);
})
->orWhere(function ($query) use ($start, $end) {
$query->whereDate('start', '>=', $start)->whereDate('start', '<=', $end);
})
// gives "General error: 1096 No tables used":
->whereIn('eventId', function ($query) use ($eventIds){
$query->whereIn('eventId', $eventIds);
})
// no effect:
// ->whereIn('eventId', $eventIds)
->get();
I tried to add it as a function and in simple form but the function leads to General error: 1096 No tables used and the other shows no effect at all, because the collection is far too large and should be only 4 items after whereIn and the orWhere selection. $eventIds is a flat array:
["P000018","P000054","P000021","P000030"]

check condition within query in laravel

$q = Order::select(
'orders.*',
'items.date_start',
'items.date_end',
'items.location_name',
'items.category_id'
)
->join('items', 'items.item_id', '=', 'orders.item_id')
->leftJoin('orders_items', function ($join) use ($user_id)
{
$join->on('orders_items.order_id', '=', 'orders.order_id')
->on('orders_items.item_id', '=', 'orders.item_id')
->where('orders_items.user_id', '=', $user_id);
})
->with('Items')
->where(function ($query) use ($select_balance) { // This is where event is in the future, or it has a balance and is not draft.
$query->where('items.date_end', '>=', Carbon\Carbon::now()->toDateString())
->orWhere(function ($query) use ($select_balance) {
$query->where(DB::raw($select_balance), '>', 0)
->whereNotIn('orders.status', [0, 79]);
});
});
i would like to set a condition if (date_start == date_end) then
$query->where('items.date_end', '>=', Carbon\Carbon::now()->toDateString())
->orWhere(function ($query) use ($select_balance) {
$query->where(DB::raw($select_balance), '>', 0)
->whereNotIn('orders.status', [0, 79]);
});
else
$query->where('items.date_end', '>', Carbon\Carbon::now()->toDateString())
->orWhere(function ($query) use ($select_balance) {
$query->where(DB::raw($select_balance), '>', 0)
->whereNotIn('orders.status', [0, 79]);
});
how to set a condition within query i try to end query after ->with(items) but that say $q-> has syntax error please guide and explain how to over come this issue
You can use conditional clauses: https://laravel.com/docs/5.5/queries#conditional-clauses
Animals::when($condition, function($query) {
$query->where('size', 'big');
})->when(!$condition, function($query)) {
$query->where('size', 'small');
})->get();
In the example, if $condition is true then we fetch big animals, otherwise we fetch small animals.

Laravel Eloquent group by relation

I'm struggling to understand how to use Eloquent/Query Builder with relationships.
I have the following:
$plantLots = PlantLot::with('controlNumber')
->whereHas('controlNumber', function ($q) use ($fromDate, $toDate) {
$q->where('created_at', '>=', $fromDate);
if($toDate != '') {
$q->where('created_at', '=<', $toDate);
}
$q->groupBy('creator_id');
})->get();
I want to group by creator_id, but I still just get a single collection of data.
What am I doing wrong?
change it to
$plantLots = PlantLot::with(['controlNumber' => function($q){
$q->groupBy('creator_id');
}])
->whereHas('controlNumber', function ($q) use ($fromDate, $toDate) {
$q->where('created_at', '>=', $fromDate)
->when($toDate != '',function($q){
$q->where('created_at', '=<', $toDate);
});
})->get();
Hope it helps.

Laravel 5: Check if event date range is not already taken

I'm creating calendar for few days events and the events can not overlap. But event can start/end when another event starts/ends.
In Laravel, in my event model table I am storing start and end date of events.
How can I check before storing new event do database, if it is valid (is not overlapping with existing events, excluding margin/boundary days) ?
In advance thank You very much for Your help.
You can use following code to get the correct counts for events booked between certain times:
$eventsCount = Events::where(function ($query) use ($startTime, $endTime) {
$query->where(function ($query) use ($startTime, $endTime) {
$query->where('start', '>=', $startTime)
->where('end', '<', $startTime);
})
->orWhere(function ($query) use ($startTime, $endTime) {
$query->where('start', '<', $endTime)
->where('end', '>=', $endTime);
});
})->count();
Use it for all variants intersections date ranges. It help for me
$rangeCount = TransferSchedule::where(function ($query) use ($from, $to) {
$query->where(function ($query) use ($from, $to) {
$query->where('date_from', '<=', $from)
->where('date_to', '>=', $from);
})->orWhere(function ($query) use ($from, $to) {
$query->where('date_from', '<=', $to)
->where('date_to', '>=', $to);
})->orWhere(function ($query) use ($from, $to) {
$query->where('date_from', '>=', $from)
->where('date_to', '<=', $to);
});
})->count();
This is just some pseudocode since you don't provide any code or your model, but depending on how your table is set up, you should be able to do it like this. This will return any events where the new event's start time or end time falls between an existing event's start and end times. This will work if your times are timestamps, or DateTime columns.
Events::where(DB::raw("? between start_time and end_time",$start))
->orWhere(DB::raw("? between start_time and end_time",$end))
->get();
->where(function ($query) use($startDate, $endDate, $currentDate) {
$query->where('start_date', '<=', $startDate)
->where('end_date', '>=', $endDate)
->where('end_date', '>', $currentDate);
})
->orWhere(function ($query) use($startDate, $endDate, $currentDate) {
$query->where('start_date', '>=', $startDate)
->where('end_date', '<=', $endDate)
->where('end_date', '>', $currentDate);
})
->orWhere(function ($query) use($startDate, $endDate, $currentDate) {
$query->where('start_date', '<=', $startDate)
->where('end_date', '>=', $startDate)
->where('end_date', '>', $currentDate);
})
->orWhere(function ($query) use($startDate, $endDate, $currentDate) {
$query->where('start_date', '<=', $endDate)
->where('end_date', '>=', $endDate)
->where('end_date', '>', $currentDate);

Laravel Query Filter different Tables with AND

I have a problem with my Larvel Query it doesn't work as desired.
It should Filter "Campaigns" with the attributes Teams, Channels, Region and Timeperiod with Start and Enddate. The Timeperiod is no problem.
The user can Filter for differen Teams/Channels/Region and can choose no, one or more Attribute, which should connect as or.
The desired Result should give all Campaign which has the selected Teams AND Channels AND Region. But at the moment I get every Campaign which has the selected Teams OR the selected Channels OR the selected Region.
public function searchCampaigns($page, $limit, $data)
{
$startDate = $data['startDate'];
$endDate = $data['endDate'];
$campaigns = Campaign::distinct()->select('campaigns.*')
->join('campaign_team', 'campaign_team.campaign_id', '=', 'campaigns.id')
->join('campaign_region', 'campaign_region.campaign_id', '=', 'campaigns.id')
->join('campaign_channel', 'campaign_channel.campaign_id', '=', 'campaigns.id')
->join('teams', 'campaign_team.team_id', '=', 'teams.id')
->join('regions', 'campaign_region.region_id', '=', 'regions.id')
->join('channels', 'campaign_channel.channel_id', '=', 'channels.id')
//Interesting Part
->whereIn('teams.id', $data['teams'])
->whereIn('regions.id', $data['regions'])
->whereIn('channels.id', $data['channels'])
->where(function ($query) use ($startDate, $endDate) {
$query->where('campaigns.start_date', '>=', $startDate)
->where('campaigns.end_date', '<=', $endDate);
})
->orWhere(function ($query) use ($startDate, $endDate) {
$query->where('campaigns.end_date', '<=', $endDate)
->where('campaigns.end_date', '>=', $startDate);
})
->orWhere(function ($query) use ($startDate, $endDate) {
$query->where('campaigns.start_date', '>=', $startDate)
->where('campaigns.start_date', '<=', $endDate);
})
->orWhere(function ($query) use ($startDate, $endDate) {
$query->where('campaigns.start_date', '<=', $startDate)
->Where('campaigns.end_date', '>=', $endDate);
}) ->orderBy('start_date', 'asc');
$result['count'] = sizeof($campaigns->lists('id'));
$result['campaigns'] = $campaigns->skip($limit * ($page - 1))->take($limit)->get();
return $result;
}
Try this one. It shall work. Let me know if any issues happen :)
public function searchCampaigns($page, $limit, $data)
{
$result = [];
// Checking Validity of Start Date
if (empty($data['startDate']) || (Carbon::createFromFormat('Y-m-d', $data['startDate']) === false))
return $result;
// Checking Validity of End Date
if (empty($data['endDate']) || (Carbon::createFromFormat('Y-m-d', $data['endDate']) === false))
return $result;
// Comparing Start & End Date
$startDate = Carbon::parse($data['startDate']);
$endDate = Carbon::parse($data['endDate']);
if($startDate->gt($endDate))
return $result;
if($endDate->lt($startDate))
return $result;
$startDate = $data['startDate'];
$endDate = $data['endDate'];
$campaigns = Campaign::distinct()->select('campaigns.*')
->join('campaign_team', 'campaign_team.campaign_id', '=', 'campaigns.id')
->join('campaign_region', 'campaign_region.campaign_id', '=', 'campaigns.id')
->join('campaign_channel', 'campaign_channel.campaign_id', '=', 'campaigns.id')
->join('teams', 'campaign_team.team_id', '=', 'teams.id')
->join('regions', 'campaign_region.region_id', '=', 'regions.id')
->join('channels', 'campaign_channel.channel_id', '=', 'channels.id')
->whereIn('teams.id', $data['teams'])
->whereIn('regions.id', $data['regions'])
->whereIn('channels.id', $data['channels'])
->where('campaigns.start_date', '>=', $startDate)
->where('campaigns.end_date', '<=', $endDate);
->orderBy('start_date', 'asc');
$result['count'] = sizeof($campaigns->lists('id'));
$result['campaigns'] = $campaigns->skip($limit * ($page - 1))->take($limit)->get();
return $result;
}

Categories