I would like to create a more readable code by eliminating too many if statements but still does the job. I have tried creating a private method and extract the date range query and return the builder instance but whenever I do that, it does not return the correct builder query result so I end up smashing everything up on this method.
Other parameters will be added soon, so the if statements would pill up very fast. :(
Any tip on how to improve would be much appreciated. Thanks!
/**
* @param array $params
*
* @param $orderBy
* @param $sortBy
*
* @return Collection
*
* Sample:
* `/orders?release_date_start=2018-01-01&release_date_end=2018-02-20&firm_id=3` OR
* `/orders?claimId=3&status=completed`
*
* Problem: Too many if statements
*
*/
public function findOrdersBy(array $params, $orderBy = 'id', $sortBy = 'asc'): Collection
{
$release_date_start = array_get($params, 'release_date_start');
$release_date_end = array_get($params, 'release_date_end');
$claimId = array_get($params, 'claimId');
$firm_id = array_get($params, 'firm_id');
$status = array_get($params, 'status');
$orders = $this->model->newQuery();
if (!is_null($release_date_start) && !is_null($release_date_end)) {
$orders->whereBetween('releaseDate', [$release_date_start, $release_date_end]);
} else {
if (!is_null($release_date_start)) {
$orders->where('releaseDate', '>=', $release_date_start);
} else {
if (!is_null($release_date_end)) {
$orders->where('releaseDate', '<=', $release_date_end);
}
}
}
if (!is_null($claimId)) {
$orders->where(compact('claimId'));
}
if (!is_null($firm_id)) {
$orders->orWhere(compact('firm_id'));
}
if (!is_null($status)) {
$orders->where(compact('status'));
}
return $orders->orderBy($orderBy, $sortBy)->get();
}
if you are interested in using collection methods then you can use when()
collection method to omit your if-else
statements. So according to your statement it will look something like:
$orders->when(!is_null($release_date_start) && !is_null($release_date_end), function($q) {
$q->whereBetween('releaseDate', [$release_date_start, $release_date_end]);
}, function($q) {
$q->when(!is_null($release_date_start), function($q) {
$q->where('releaseDate', '>=', $release_date_start);
}, function($q) {
$q->when(!is_null($release_date_end), function($q) {
$q->where('releaseDate', '<=', $release_date_end);
})
})
})
->when(!is_null($claimId), function($q) {
$q->where(compact('claimId'));
})
->when(!is_null($firm_id), function($q) {
$q->orWhere(compact('firm_id'));
})
->when(!is_null($status), function($q) {
$q->where(compact('status'));
})
For more information you can see conditional-clauses in documentation. Hope this helps.
One option you can use is ternary operation in php like this:
$claimId ? $orders->where(compact('claimId')) : ;
$firm_id ? $orders->orWhere(compact('firm_id')) : ;
$status ? $orders->where(compact('status')) : ;
It would be cleaner than is statements code.
Another option you can use in laravel is Conditional Clauses
Thanks for your suggestions but I came up with another solution:
/**
* @param array $params
*
* @param $orderBy
* @param $sortBy
*
* @return Collection
*/
public function findOrdersBy(array $params, $orderBy = 'id', $sortBy = 'asc'): Collection
{
$release_date_start = array_get($params, 'release_date_start');
$release_date_end = array_get($params, 'release_date_end');
$orders = $this->model->newQuery();
if (!is_null($release_date_start) && !is_null($release_date_end)) {
$orders->whereBetween('releaseDate', [$release_date_start, $release_date_end]);
} else {
if (!is_null($release_date_start)) {
$orders->where('releaseDate', '>=', $release_date_start);
} else {
if (!is_null($release_date_end)) {
$orders->where('releaseDate', '<=', $release_date_end);
}
}
}
$fields = collect($params)->except($this->filtersArray())->all();
$orders = $this->includeQuery($orders, $fields);
return $orders->orderBy($orderBy, $sortBy)->get();
}
/**
* @param Builder $orderBuilder
* @param array $params
*
* @return Builder
*/
private function includeQuery(Builder $orderBuilder, ... $params) : Builder
{
$orders = [];
foreach ($params as $param) {
$orders = $orderBuilder->where($param);
}
return $orders;
}
/**
* @return array
*/
private function filtersArray() : array
{
return [
'release_date_start',
'release_date_end',
'order_by',
'sort_by',
'includes'
];
}
The main factor on the private method includeQuery(Builder $orderBuilder, ... $params)
which takes $params
as variable length argument . We just iterate the variables being passed as a query parameter /orders?code=123&something=test
and pass those as a where()
clause in the query builder.
Some parameters may not be a property of your object so we have to filter only the query params that match the object properties. So I created a filtersArray()
that would return the parameters to be excluded and prevent an error.
Hmmm, actually, while writing this, I should have the opposite which is only()
otherwise it will have an infinite of things to exclude. :) That would be another refactor I guess. :P
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.