Как правильно использовать несколько функций SqlSelect set /add where

#php #silverstripe

#php #silverstripe

Вопрос:

Я собираю SQL-запрос, используя класс SilverStripes SQLSelect с некоторыми дополнительными фильтрами (frontend).

При попытке использовать addWhere() с параметрами запрос не дает результатов. Например:

 $sql->useConjunction();
        
$sql->addWhere(['SiteTree.ClassName' => 'ResourcePage']);
        
if (self::$Filters['Tags'])
{
    $sql->addLeftJoin('ResourcePage_Tags', 'ResourcePage_Tags.ResourcePageID = SiteTree.ID');
    $sql->addWhere(['ResourcePage_Tags.ResourceTagID IN (?)' => implode(',', self::$Filters['Tags'])]);
}

if (self::$Filters['Types'])
{
    $sql->addLeftJoin('ResourcePage_Types', 'ResourcePage_Types.ResourcePageID = SiteTree.ID');
    $sql->addWhere(['ResourcePage_Types.ResourceTypeID IN (?)' => implode(',', self::$Filters['Types'])]);
}
  

Если я обрабатываю это как строку, я получаю результаты (например, я ожидаю тестирования с помощью ручного SQL). Например:

 $sql->useConjunction();
        
$sql->addWhere("SiteTree.ClassName = 'ResourcePage'");

if (self::$Filters['Tags'])
{
   $sql->addLeftJoin('ResourcePage_Tags', 'ResourcePage_Tags.ResourcePageID = SiteTree.ID');
   $sql->addWhere('ResourcePage_Tags.ResourceTagID IN ('.implode(',', self::$Filters['Tags']).')');
}

if (self::$Filters['Types'])
{
    $sql->addLeftJoin('ResourcePage_Types', 'ResourcePage_Types.ResourcePageID = SiteTree.ID');
    $sql->addWhere('ResourcePage_Types.ResourceTypeID IN ('.implode(',', self::$Filters['Types']).')');
}
  

Сгенерированный (упрощенный) запрос, найденный с помощью $sql->__toString() , является:

 SELECT
    DISTINCT SiteTree.*
FROM
    SiteTree 
LEFT JOIN 
    "ResourcePage_Tags" ON ResourcePage_Tags.ResourcePageID = SiteTree.ID 
LEFT JOIN 
    "ResourcePage_Types" ON ResourcePage_Types.ResourcePageID = SiteTree.ID
WHERE 
 (SiteTree.ClassName = ?)
 AND (ResourcePage_Tags.ResourceTagID IN (?))
 AND (ResourcePage_Types.ResourceTypeID IN (?))

  

Часть параметров приведенного выше вывода представляет собой массив:

 'ResourcePage',
1 => '38'
2 => '5,4'
  

Пропущенные части запроса — это некоторые предложения MATCH AGAINST и LIMIT ORDER BY , которые всегда присутствуют.

Что я сделал не так, чтобы получить два разных поведения между string и параметризованной версией?

Ответ №1:

Первый пример, который у вас был, который использовал in (?) , а затем передавал массив значений, не будет выполняться правильно, потому что предполагается, что ? это одно значение при использовании prepare. Это означает, что теперь вы запрашиваете единицу, ResourceTypeID которая равна array_value1,array_value2 . Поэтому вам необходимо иметь заполнитель ( ? ) для каждого элемента в self::$Filters['Tags'] массиве.

У фреймворка есть вспомогательный метод для достижения этого, например:

 $placeholders = DB::placeholders(self::$Filters['Tags'])
$query->addWhere([
  "ResourcePage_Types.ResourceTypeID IN ($placeholders)" => self::$Filters['Tags']
]);
  

Комментарии:

1. Ну ладно. Я видел этот пример DB::prepared_query('DELETE FROM "SiteTree" WHERE "SiteTree"."ShowInMenus" = ?', [0]); в документах. Приветствую это.