QueryBuilder с foreach и несколькими параметрами

#symfony #updates #query-builder

#симфония #Обновления #конструктор запросов #symfony

Вопрос:

Я хочу иметь общий метод обновления, который получает json с {field1:value1,.. field4:value4} и обновляет их все. Где field — это имя поля из таблицы в БД. Это может быть только одно поле для обновления, но также и несколько.

В моем контроллере symfony :

  /**
     * @Route("/update", name="template_update", methods={"POST"})
     */
    public function update(Request $request, TemplateRepository $templateRepository): Response
    {
        $data = json_decode($request->getContent(), true);
        $fields = $data["data"];
        $qb = $templateRepository->createQueryBuilder('t');

        foreach ($fields as $field => $value) {
            dump($field);
            dump($value);
            $q = $qb->update(Template::class,'t')
            ->set("t." . $field . "", '?1')
            ->where('t.id = ?2')
            ->setParameter(1, $value)
            ->setParameter(2, $data["id"])
            ->getQuery();
            dump($q);
            $p = $q->execute();
        }
        return new JsonResponse(["response" => $p]);
    }
  

В первом цикле все в порядке : введите описание изображения здесь

Но во втором цикле предыдущий параметр сохраняется и перезаписывается этим последним запросом : введите описание изображения здесь

Что я делаю не так? И есть ли лучший способ избежать нескольких запросов и сделать это в одном уникальном запросе?

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

1. Я думаю, вам нужен новый конструктор запросов для каждого запроса на обновление.

2. Вот и все, я этого не вижу

3. Спасибо @IwanWijaya!

4. Я имею в виду, что вам нужно запускать createQueryBuilder() для каждого цикла. это может сработать, но написание такого кода на самом деле небезопасно и неэффективно.

Ответ №1:

Ок ответ был я объявляю только один раз мой querybuilder за пределами foreach. Поместите его внутрь foreach, и больше ошибок не будет.

Я также выясняю, как это сделать в одном запросе :

     $qb = $templateRepository->createQueryBuilder('t');
    $qb->update(Template::class, 't');
    $count = 0;
    foreach ($fields as $field => $value) {
        $qb->set("t." . $field . "", '?' . $count . '')
            ->setParameter($count, $value);
        $count  ;
    };
    $q = $qb->where('t.id = ?' . $count . '')
        ->setParameter($count, $data["id"])
        ->getQuery();
    $p = $q->execute();
  

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

1. Просто имейте в виду, что, поскольку $field поступает из внешнего источника, вы уязвимы для sql-инъекций. В отличие от полей данных, обработка имен столбцов не выполняется. По крайней мере, вам нужно проверить $field .

2. Это хороший момент, вы имеете в виду просто strip_tags и тому подобное в $field / $value ?

3. Я бы просто получил массив допустимых имен полей и проверил, что $field является одним из них.

4. Интересно, могли бы вы просто извлечь шаблон из базы данных и вызвать соответствующие установщики, а затем сбросить в БД и получить только один запрос, и он будет правильно экранирован по умолчанию… очевидно, работает только в том случае, если у вас есть нормальное сопоставление между свойствами и именами столбцов

5. или даже больше, используйте десериализатор для заполнения объекта данными … ; o)