gajus/klaus

User input interpreter for constructing SQL WHERE clause.

0.1.0 2014-04-25 15:55 UTC

This package is not auto-updated.

Last update: 2024-10-26 14:43:02 UTC


README

Build Status Coverage Status Latest Stable Version License

User input interpreter for constructing SQL WHERE clause. Klaus can build complex WHERE clauses of variable depth and with different grouping conditions.

Documentation

Preparing Query

Raw query consists of the grouping operator definition (AND or OR) and condition. There are two types of conditions:

Comparison Condition

Comparison consists of user input name, value and the comparison operator, e.g.

[
    'name' => 'foo_name', // User input name
    'value' => '1', // User input value
    'operator' => '=' // Condition operator
]

Group Condition

The condition itself can define new group, e.g.

$query = [
    'group' => 'AND',
    'condition' => [
        ['name' => 'foo_name', 'value' => '1', 'operator' => '='],
        ['name' => 'bar_name', 'value' => '2', 'operator' => '='],
        [
            'group' => 'OR',
            'condition' => [
                ['name' => 'foo_name', 'value' => '1', 'operator' => '='],
                ['name' => 'bar_name', 'value' => '2', 'operator' => '=']
            ]
        ]
    ]
]

A complete query must include at least one group and at least one comparison operator.

Mapping Using Input

Mapping is used to restrict columns that can be included in the query, as well as to provide support for columns that depend on alias or even more complicated constructs.

SELECT
    `f1`.`name`,
    `b1`.`name`
FROM
    `foo` `f1`
INNER JOIN
    `bar` `b1`
ON
    [..]

In the above example, you need to define relation between the parameter name that you are using in the query and the column name in the SQL query, e.g.

$map = [
    'foo_name' => '`f1`.`name`',
    'bar_name' => '`b1`.`name`'
];

Buildng the WHERE Clause

The preceeding examples explain how to prepare data for the Where constructor.

/**
 * @param array $query
 * @param array $map Map input name to the aliased column in the SQL query, e.g. ['name' => '`p1`.`name`'].
 */
$where = new \Gajus\Klaus\Where($query, $map);

We are going to use the SQL from the previous example to construct a prepared statement and execute it.

The WHERE clause itself is generated using getClause method:

/**
 * @return string SQL WHERE clause representng the query.
 */
$where->getClause();

If query does not produce a condition, then getClause will always return 1=1, e.g.

$sql = "
SELECT
    `f1`.`name`,
    `b1`.`name`
FROM
    `foo` `f1`
INNER JOIN
    `bar` `b1`
ON
    [..]
WHERE
    {$where->getClause()}
    ";

In the above example, $sql is:

SELECT
    `f1`.`name`,
    `b1`.`name`
FROM
    `foo` `f1`
INNER JOIN
    `bar` `b1`
ON
    [..]
WHERE
    `f1`.`name` = :foo_name_0 AND
    `b1`.`name` = :bar_name_1 AND
        (
            `f1`.`name` = :foo_name_2 OR
            `b1`.`name` = :bar_name_3
        )

To execute the query, you have to build PDOStatement, e.g.

$sth = $db->prepare($sql);

and execute it using the input data:

/**
 * @return array Input mapped to the prepared statement bindings present in the WHERE clause.
 */
$input = $where->getInput();

$sth->execute($input);

In the above example, $input is equal to:

[
    'foo_name_0' => '1',
    'bar_name_1' => '2',
    'foo_name_2' => '1',
    'bar_name_3' => '2',
]

Input Template

For basic search you can use Gajus\Klaus\Where::queryTemplate.

  • Basic query template takes name => value pairs and converts them to WHERE clause grouped using AND.
  • Empty values are discarded.
  • Values begning with % will use LIKE comparison.
  • Values endding with % will use LIKE comparison.
  • Values that do not contain % or where % is not at the begining or end of the query will use = comparison.

Example

$query = \Gajus\Klaus\Where::queryTemplate(['foo' => 'bar', 'baz' => 'qux%']);

// $query is now eq. to:

$query = [
    'group' => 'AND',
    'condition' => [
        ['name' => 'foo', 'value' => 'bar', 'operator' => '='],
        ['name' => 'baz', 'value' => 'qux%', 'operator' => 'LIKE']
    ]
];

// Which you then pass to the Where constructor.

$where = new \Gajus\Klaus\Where($query, ['foo' => '`foo`', 'baz' => '`baz`']);

$sth = $db->prepare("SELECT `foo`, `baz` FROM `quux` WHERE {$where->getClause()}");
$sth->execute($where->getInput());

// ..

Alternatives

elasticsearch (ES) provides an API with a query DSL. The only downside of using ES is that it requires data dupliction.