php - условные параметры where и mysql

0

У меня есть форма с несколькими полями, используемыми для функции поиска в моем приложении. Может быть любая комбинация для параметров поиска, все могут быть заполнены или просто 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

  • 2
    OR ? = '' Это определенно не законно и приведет к ошибкам компиляции
  • 0
    Для ? = '' будет работать только если? заменяется литералом, а не именем столбца. Если вам нужно проверить, является ли значение пустым, сделайте это в коде PHP и пропустите его из кода SQL. Вы бы лучше обслужили использование именованных параметров в PDO. Таким образом, вы можете создать предложение where, а затем связать все возможные параметры. Те, которые не включены в оператор SQL, будут игнорироваться.
Показать ещё 2 комментария
Теги:
conditional

1 ответ

0
Лучший ответ

Использование 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();

ПРИМЕЧАНИЕ. Не проверено, может быть опечаток.

  • 0
    Вау, спасибо. Это некоторый тяжелый код PHP / Mysql. Я все еще новичок, когда дело доходит до этого, поэтому мне нужно некоторое время, чтобы проанализировать / понять, как все части этого работают. Используя ваш код как есть (за исключением редактирования переменной $ qtr в $ qstr, я выдаю мне ошибку bindParam (Uncaught Error: вызов функции-члена bindParam () в логическом)) Если я правильно понял, будет / должен ли этот код работать как До тех пор, пока я использую "searchAlias" и так четвертый в качестве параметров POST? (что я делаю). И будет ли работать метка времени, когда у меня есть два разных параметра POST (от даты и до даты в формате YYYY-MM-DD?).
  • 0
    Обновление: теперь я понимаю концепцию и код. Я не понял разницу между mysqli и PDO, поэтому неудивительно, что соединение mysqli не сработало. Однако теперь я добавил соединение PDO, которое работает нормально. Мне удалось запустить запрос, когда я заполнил все поля ввода, а также установил подстановочный знак в false. Когда я устанавливаю подстановочный знак в true, кажется, что не удается связать параметры. (Невозможно передать параметр 2 по ссылке в). Когда я не заполняю все значения, я получаю следующее: Неверный номер параметра: количество связанных переменных не соответствует количеству токенов в.
Показать ещё 5 комментариев

Ещё вопросы

Сообщество Overcoder
Наверх
Меню