У меня есть форма с несколькими полями, используемыми для функции поиска в моем приложении. Может быть любая комбинация для параметров поиска, все могут быть заполнены или просто 1 (или любой другой).
На данный момент соответствующая часть PHP-кода выглядит так (что на самом деле работает, но я боюсь и думаю, что это ужасно плохой дизайн/реализация):
$whereClause = "";
if (!empty($_POST['searchAlias'])) {
$searchAlias = "%{$_POST['searchAlias']}%";
$whereClause .= " AND (users.alias LIKE ? OR users.alias LIKE ?)";
} else {
$searchAlias = "";
$whereClause .= " AND (users.alias LIKE ? OR users.alias LIKE ?)";
}
if (!empty($_POST['searchLink'])) {
$searchLink = "%{$_POST['searchLink']}%";
$whereClause .= " AND (posts.homepage LIKE ? OR posts.homepage LIKE ?)";
} else {
$searchLink = "";
$whereClause .= " AND (posts.homepage LIKE ? OR ? = '')";
}
if (!empty($_POST['searchComment'])) {
$searchComment = "%{$_POST['searchComment']}%";
$whereClause .= " AND (posts.comment LIKE ? OR posts.comment LIKE ?)";
} else {
$searchComment = "";
$whereClause .= " AND (posts.comment LIKE ? OR ? = '')";
}
if (!empty($_POST['searchCategory'])) {
$searchCategory = $_POST['searchCategory'];
$whereClause .= " AND (posts.category LIKE ? OR posts.category LIKE ?)";
} else {
$searchCategory = "";
$whereClause .= " AND (posts.category LIKE ? OR ? = '')";
}
$stmt = $connection->prepare("SELECT users.alias, posts.postId,
categories.category, posts.homepage, posts.comment, posts.timestamp,
posts.upvotes FROM ((posts INNER JOIN categories ON posts.category =
categories.id) INNER JOIN users ON posts.userId = users.userId)
WHERE 1=1 $whereClause ORDER BY postId DESC LIMIT 300");
$stmt->bind_param("ssssssss", $searchAlias,$searchAlias,
$searchLink,$searchLink, $searchComment,$searchComment,
$searchCategory,$searchCategory);
Я должен добавить, что у меня также есть 2 поля ввода даты (от и до даты), которые также могут быть включены в поиск, они не добавляются в текущий PHP-код, так как я еще не исправил их.
Как вы можете видеть, я уверен, что параметры, установленные из данных формы, добавляются в whereClause - всегда с двумя? чтобы типы и переменные bind_param могли оставаться неизменными все время.
Итак, это "приемлемое" решение или есть ли способ сделать это намного чище и проще? Я пробовал искать разные решения, но я не слишком хорошо разбираюсь в них или не достаточно хорошо разбираюсь в решениях.
Любая помощь или идея оцениваются!
С уважением, Eken
Использование PDO с именованными параметрами упростило бы эту задачу, если при добавлении дополнительных параметров поиска. Он также будет учитывать параметры поиска, в которых значение сравнивается с несколькими столбцами, или требует ввода типа значения поиска. Возможно, вам захочется добавить "%" до и после значений для условий LIKE. Это можно сделать, добавив значения $ _POST в массив и привязывая значения массива вместо значений $ _POST.
РЕДАКТИРОВАТЬ
Я изменил свою первую публикацию, чтобы найти подходящую дату, и разрешить добавление подстановочных знаков, подобных сравнениям. Код также может быть легко изменен, чтобы обеспечить двух проверок значений, например, между датами.
$postVals = array();
foreach($_POST as $varname => $varval) {
$postVals[$varname] = $varval;
}
$wherePieces = array();
$tests = array(
"searchAlias" => array("where" => "user.alias LIKE :searchAlias","addWildCard" => false),
"searchLink" => array("where" => "posts.homepage LIKE :searchLink","addWildCard" => true),
"searchComment" => array("where" => "posts.comment LIKE :searchComment","addWildCard" => true),
"searchCategory" => array("where" => "posts.category LIKE :searchCategory","addWildCard" => false),
"searchTimestamp" => array("where" => "CAST(posts.timestamp AS DATE) = CAST(:searchTimestamp AS DATE)","addWildCard" => false)
);
foreach($tests as $postname => $wherePart) {
if(isset($_POST[$postname]) && $_POST[$postname] != '') {
$wherePieces[] = $wherePart['where'];
}
}
$whereClause = "WHERE " . implode(" AND ",$wherePieces);
$qstr = "SELECT
users.alias,
posts.postId,
categories.category,
posts.homepage,
posts.comment,
posts.timestamp,
posts.upvotes
FROM posts
INNER JOIN categories
ON posts.category = categories.id
INNER JOIN users
ON posts.userId = users.userId)
$whereClause
ORDER BY postId DESC
LIMIT 300";
$stmt = $connection->prepare($qstr);
foreach($tests as $postname => $wherePart) {
if(isset($_POST[$postname]) && $_POST[$postname] != '') {
if($wherePart["addWildCard"]) {
$postVals[$postname] = '%'.$postVals[$postname].'%';
}
$stmt->bindParam(':'.$postname,$postVals[$postname]);
}
}
$stmt->execute();
ПРИМЕЧАНИЕ. Не проверено, может быть опечаток.
OR ? = ''
Это определенно не законно и приведет к ошибкам компиляции