Doctrine построитель запросов - где IN с нестроковыми именами столбцов не может быть сгенерирован - PullRequest
1 голос
/ 06 мая 2020

Я не могу уснуть из-за этого, либо мне не хватает чего-то действительно очевидного, либо это невозможно сделать вот так.

У меня есть эта Doctrine штука с построителем запросов:

    $this->queryBuilder
        ->where('entity.id != ' . $id)
        ->andWhere(
            $this->queryBuilder->expr()->andX(
                $this->queryBuilder->expr()->in(":validatedValue", ['slug', 'title', 'content'])
            )
       )
       ->setParameter('validatedValue', $value);

Теперь он производит что-то вроде этого:

SELECT
    p0_.id AS id_0,
    p0_.title AS title_1,
    p0_.teaser AS teaser_2,
    p0_.content AS content_3,
    p0_.slug AS slug_4
FROM
    posts p0_
WHERE
    p0_.id <> 1
    AND 'my-string-value-something something' IN('slug', 'title', 'content')

У меня проблема с этой конкретной строкой:

AND 'my-string-value-something something' IN('slug', 'title', 'content')

Я хочу иметь возможность проверять фактические столбцы, поэтому я должен выдать что-то вроде этого:

AND 'my-string-value-something something' IN(slug, title, content)

Как вы заметили, правильная версия, которую я хочу иметь, в ней нет кавычек вокруг имен полей, если это имеет смысл. Если они будут там, это будет рассматриваться просто как строка, а не как фактический столбец в таблице.

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

Кто-нибудь вообще знает, как я могу сделать это с помощью строителя? Могу ли я сделать это с помощью компоновщика или для этого нужно просто использовать DQL или простой SQL?

1 Ответ

0 голосов
/ 08 мая 2020

Что касается того, что я хотел делать, я обнаружил, что это просто невозможно, так как я хотел это сделать.

Я думаю, что, судя по всему, doctrine всегда будет заключать мои элементы в массив в кавычки. Не думаю, что его можно выключить. Даже если есть какой-то другой умный способ справиться с этим, это кажется слишком большим усилием для такой простой вещи.

/**
     * Creates an IN() expression with the given arguments.
     *
     * @param string $x Field in string format to be restricted by IN() function.
     * @param mixed  $y Argument to be used in IN() function.
     *
     * @return Expr\Func
     */
    public function in($x, $y)
    {
        if (is_array($y)) {
            foreach ($y as &$literal) {
                if ( ! ($literal instanceof Expr\Literal)) {
                    $literal = $this->_quoteLiteral($literal);
                }
            }
        }

        return new Expr\Func($x . ' IN', (array) $y);
    }

Именно так я получаю нежелательную кучу цитат из Doctrine.

$literal = $this->_quoteLiteral($literal);

Что касается того, как я решил свою проблему, я сделал именно то, что @Bananaapple предложил в комментарий в моем посте. Итак, теперь мой код выглядит так:

// build conditions to determine which fields should be checked for the value
foreach ($constraint->fields as $field) {
    $fieldsConditions[] = $this->queryBuilder->expr()->eq('entity.' . $field, ':value');
}


// we should always have fields as this is taken care of before we even get to this point
if (!empty($fieldsConditions)) {
    $this->queryBuilder->andWhere(
        $this->queryBuilder->expr()->orX(...$fieldsConditions)
    )->setParameter('value', $value);
 }

Надеюсь, это кому-то поможет.

...