I build SQL query with a method and then return it and use it.
$query = $this->buildSearchQuery($searchParams);
return $this->db->query($query);
Unfortunately this throw me an error:
SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''SELECT * FROM candidates WHERE firstname = ? AND surname = ?','Dante', 'Hickman' at line 1
I was searching for it because this looks like SQL syntax fail of previous script which build query so I did simple thing I dump this $query before I used it.
Dump return this:
"'SELECT * FROM candidates WHERE firstname = ? AND surname = ?','Dante', 'Hickman'" (81)
Which is correctly, string with 81 chars. After this, I try to put this to original query instead of variabile and it looks like this:
return $this->db->query('SELECT * FROM candidates WHERE firstname = ? AND surname = ?','Dante', 'Hickman');
This secod script run correcty so it looks query is build correctly, but still error. I am missing something?
I hope for any advise which can help me solve this problem.
p.s. Syntax of that query is from nette framework but system should be the same.
EDIT: adding buildSearchQuery()
function buildSearchQuery($searchParams)
{
$column = "";
$values = "";
$col = "";
$i=0;
// Trim to make sure user doesn't enter space there
if((trim($searchParams->firstname)))
{
$column .= "firstname,";
$i++;
}
if((trim($searchParams->surname)))
{
$column .= "surname,";
$i++;
}
if((trim($searchParams->specialization)))
{
$column .= "specialization,";
$i++;
}
if($searchParams->english !== NULL)
{
$column .= "english,";
$i++;
}
if($searchParams->german !== NULL)
{
$column .= "german,";
$i++;
}
if($searchParams->russian !== NULL)
{
$column .= "russian,";
$i++;
}
if($searchParams->french !== NULL)
{
$column .= "french,";
$i++;
}
if($searchParams->school !== NULL)
{
$column .= "school,";
$i++;
}
if((trim($searchParams->registrationDate)))
{
$column .= "registrationDate";
$i++;
}
if($i > 0)
{
// If number of columns is bigger then 0 (if user fill atleast one input)
$columns = explode(",", $column);
// Create list of values for query (name of columns and values)
foreach($columns as $c)
{
if (isset($searchParams->$c)) {
$values .= "'".$searchParams->{$c}."', ";
$col .= $c." = ? AND ";
}
}
// Remove last "," and space
$values = substr_replace($values, "", -2);
$col = substr_replace($col, "", -5);
$query = $col."',".$values;
$query = "'SELECT * FROM candidates WHERE ".$query;
//$query = substr($query, 0, -1); //remove last char ( ' in this case)
return $query;
}
else
{
$query = "SELECT * FROM candidates";
return $query;
}
}
The comments above are correct, you are passing a string as the only argument, instead of multiple arguments query
expects.
One possible solution is creating an array and calling the method with array items as arguments (e.g. using call_user_func_array). You can however do better.
Nette\Database is quite powerful and it can build the query for you. When you pass an associative array like ["column1" => "value1", "column2" => "value2"]
as the only argument of where
method, it will create corresponding WHERE column1 = 'value1' AND column2 = 'value2'
clause. And of course it will securely escape the values to prevent SQL injection.
You can, therefore, simplify your code into something like following:
$columns = ["firstname", "surname", "specialization", "english", "german", "russian", "french", "school", "registrationDate"];
$conditions = [];
foreach ($columns as $c) {
if (isset($searchParams->$c) && trim($searchParams->$c) !== "") {
$conditions[$c] = $searchParams->{$c};
}
}
return $this->db->table('candidates')->where($conditions);
No if–else statement is needed as when the array is empty, NDB correctly doesn’t append the WHERE clause.