You basically have 3 choices
Create separate methods that search on something specific. This would be set methods with pre-defined inputs.
Make it somewhat flexible but have separate methods. This would have set methods but with some flexabillity in the inputs.
Make it supper flexible so it can handle most queries.
This last one is non-trivial ( meaning hard ) coding wise, but once it's setup it could handle most everything you need. Not to mention it's "cool" so I will cover that in some detail.
Now what I would do is use JSON, because it's gonna give you way more flexibility structure wise. You can always use base64_encode()
or some other encoding to sneak it into the $_GET
array without issues with the url characters, or you can use $_POST
for it. However you want to get it to the server is cool with me.
I would use a schema like this
query = {
"groupOp":"AND",
"expr":[],
"group" : [{
"groupOp":"OR",
"expr":[{
"field":"id",
"op":"eq",
"value":"2"
},{
"field":"id",
"op":"eq",
"value":"3"
}],
"group" : []
},{
"groupOp":"AND",
"expr":[{
"field":"created_date",
"op":"gte",
"value":"2017-10-01"
},{
"field":"created_date",
"op":"lte",
"value":"2017-10-31"
}],
"group" : []
}],
}
Which would roughly work out ( provided a table is supplied )
SELECT
*
FROM
tbl
WHERE
( id = 2 OR id = 3 )
AND
(created_date >= "2017-10-01" AND created_date <= "2017-10-31" )
Now just to point this out, the groupOp
and group
is very important for even simple queries like above. Compare the above query with this one.
SELECT
*
FROM
tbl
WHERE
id = 2 OR id = 3
AND
created_date >= "2017-10-01" AND created_date <= "2017-10-31"
-note- You can use other $_GET
parameters for things like the sort order, sort index, table, limits etc.. ( like ?sort_index=id&sort_order=DESC&query=AJGEDC
)
The groups denote sets of ( )
, without them this second query has a whole different meaning. This is an Exclusive OR, because we need to compare the IDs as a set, then compare the date range. Without that we could match id=2
without the date range.
So now that I explained the theory you will have to write something ( probably a recursive function ) to compile the JSON into SQL
The basic rules would be.
group: a set of expressions ( expr )
groupOp: how expressions relate to one another within a group,and how nested groups relate to those expressions
expr: a set of query segments
field: the name of the column you want to compare
op: how the field is related to the data, for example:
eq = equal, gte = greater then or equal, gt = greater then etc...
value: the value to compare against.
A few things to note for Security:
Never ever concatenate user supplied strings into your sql, without checking them first. If you do that you open yourself up to all kinds of Sql Injection nastyness. So take their column names from field
and make sure they exist in the table the query is for before using them.
Use something like SHOW TABLES
to get a list of tables from the DB, then compare user supplied tables with this list.
Use something like SHOW COLUMNS FROM table
to get the table schema, then compare user supplied columns with this list.
Always use Prepared Statements. So build your query with placeholders, and an array of inputs. Then prepare and execute the query. such as SELECT ... WHERE id = :expr1..
and [':expr1' => 2]
.
If you allow sorting and limit, same thing applies don't concatenate, anything. Don't take shortcuts on security.
One other example with nested groups
query = {
"groupOp":"AND",
"expr":[],
"group" : [{
"groupOp":"OR",
"expr":[{
"field":"id",
"op":"eq",
"value":"2"
},{
"field":"id",
"op":"eq",
"value":"3"
}],
"group" : [{
"groupOp":"AND",
"expr":[{
"field":"id",
"op":"in",
"value":[5,6,7]
},{
"field":"cat",
"op":"eq",
"value":'product'
}
}]
}],
}
With this being the SQL
SELECT
*
FROM
table
WHERE
(
id=2
OR
id=3
OR
(
id IN( 5,6,7 )
AND
cat = 'product'
)
)
This query would find records with an id
of 2,3
OR records with id
Of 5,6,7
And a cat
of "product".
You can also do them simple too:
{
"expr":[{
"field":"id",
"op":"eq",
"value":"2"
}]
}
With SQL like this
SELECT
*
FROM
table
WHERE
id=2
So you can see by using JSON, we can have the complexity we would need for this, which would be hard to achieve using just URL query parameters. And trust me, something like this will need that added level of complexity at some time, so you might as well build it in to begin with.
Even with that added level of detail, you will still probably want multiple methods to deal with things like Joins and multiple tables. I don't know your exact use case, so maybe you only need it for one table. But, it can start to get real messy if you put to much detail in it. It's a balancing act.
I've built things like this before and they work pretty well, most the time it's pretty purpose built so I don't have anything that doesn't have a bunch of dependencies I can give you. And I don't have the time to write the entire thing up for you right now, as I have to change this light fixture ... long story.
Anyway, hope those Ideas help ( good Luck! )