Supporting complex selects
Sometimes you might need to conditionally include some columns through some query scopes that might not be in the original database table. A common scenario is including distance for coordinate fields when a user supplies a latitude and longitude.
For these scenarios, you can override the modifyQuery
method to call these scopes.
// IslandsController.php
protected function modifyQuery(\Spatie\QueryBuilder\QueryBuilder $query): \Spatie\QueryBuilder\QueryBuilder
{
if (request()->has('lat') && request()->has('lng')) {
$fields = $this->fields()->isNotEmpty() ? $this->fields()->get('_') : [];
if ($this->sorts()->contains('distance') || $this->sorts()->contains('-distance') || (is_array($fields) && in_array('distance', $fields))) {
$query->withDistance('islands.coordinates', new Point(request()->input('lat'), request()->input('lng'), Srid::WGS84));
}
}
return $query;
}
Notice the calls to the $this->sorts()
and $this->fields()
methods. These are helper methods to retrieve the sorts
and fields
of the current QueryBuilder
request.
The following helper methods are included in the Api controllers.
sorts()
fields()
includes()
filters()
appends()
You can use the modifyQuery
method to conditionally eager load relations as well to prevent N + 1 queries.
protected function modifyQuery(\Spatie\QueryBuilder\QueryBuilder $query): \Spatie\QueryBuilder\QueryBuilder
{
$fields = $this->fields()->isNotEmpty() ? $this->fields()->get('_') : [];
if ((is_array($fields) && in_array('formatted_name', $fields)) || $this->appends()->contains('formatted_name')) {
$query->with('atoll');
}
return $query;
}
The $this->fields()->get('_')
will return the fields requested for the main model.
For complex selects, use the getAllowedDynamicFields
method to allow these fields to be included.
public function getAllowedDynamicFields(): array
{
$fields = [];
if (request()->has('lat') && request()->has('lng')) {
$fields[] = 'distance';
}
return $fields;
}
You may need to also dynamically set the allowed sorts as well.
public function getAllowedSorts(): array
{
$sorts = [
'id',
'created_at',
'updated_at',
'name',
'code',
'land_survey_code',
'order_column',
];
if (request()->has('lat') && request()->has('lng')) {
$sorts[] = 'distance';
}
return $sorts;
}