0

I'm working on a API with FlightPHP and PHPActiveRecord that returns an array of Reports optionally filtered through url query string parameters.

$allowed = ['author' => 'author_id', 'owner' => 'owner_id'];
$options = build_options(Flight::request(), $allowed);
$reports = Report::all($options);

The method build_options creates the array with all query options, in this case the WHERE clauses deleting those columns not allowed and ignoring not passed parameters.

function build_options($request, $allowed) {
  $clauses = array_map(function($column, $value) {
    return "($column = :$value OR :$value IS NULL)";
  }, $allowed, array_keys($allowed));
  $where = implode($clauses, ' AND ');
  $params = array_intersect_key($request->query->getData(), $allowed);
  return ['conditions' => [$where, $params]];
}

This function creates a WHERE clause like:

(author_id = :author OR :author IS NULL) AND (owner_id = :owner OR :owner IS NULL)

but it seems PHPActiveRecord does not accept named placeholders. The only issue in their GitHub asking about this is from 2010 and was closed.

Is there any other way to elegantly filter the query with optional parameters?

- EDIT -

I've worked on a workaround with positional placeholders that works without named placeholders. I still think a version with named placeholder looks cleaner and more understandable.

function build_options($request, $allowed) {
  $params = array_intersect_key($request->query->getData(), $allowed);
  $clauses = array_map(function($param) use ($allowed) {
    return "$allowed[$param] = ?";
  }, array_keys($params));
  $where = implode($clauses, ' AND ');
  return ['conditions' => array_merge([$where], array_values($params))];
}
4

0 回答 0