Как написать / расширить пользовательскую функцию DQL для Cast (X $ сравнениеOperator Y) в Doctrine?(Цель: показать связанные объекты) - PullRequest
1 голос
/ 07 апреля 2019

Для отображения связанных статей на веб-сайте мне нужна функция Cast (). Мой запрос выглядит так:

SELECT
    *,
    (CAST(a.uploader = ?1 AS UNSIGNED)
    + CAST(a.param2 = ?2 AS UNSIGNED)
    ...
    ) AS matches_count
FROM articles AS a
ORDER BY matches_count DESC

Подсчитывает совпадения и сортирует по наибольшему количеству match_counts.

Проблема в том, что в доктрине нет встроенной функции Cast ().

После нескольких часов проб и ошибок я обнаружил уже доступную пользовательскую функцию DQL: https://github.com/beberlei/DoctrineExtensions/blob/master/src/Query/Mysql/Cast.php

Я зарегистрировал это в моем doctrine.yml. Но это не работает, потому что ожидает Cast(X AS Y), а не Cast(Y $comparisonOperator X).

Когда я использую это в моем хранилище, например:

$this->createQueryBuilder('a, (CAST(author=25 AS UNSIGNED) AS matches_count)')
            ->getQuery()
            ->getResult()
            ;

Я получаю эту ошибку, потому что она не ожидает оператора сравнения:

[Syntax Error] line 0, col 29: Error: Expected Doctrine\ORM\Query\Lexer::T_AS, got '='

Вы знаете, как, возможно, расширить этот класс, а не Cast(Y $comparisonOperator X) вместо Cast(X AS Y)? Я не нашел решения в интернете и пробовал его часами.

Заранее спасибо, что нашли время написать ответ!

Обновление:

Я изменил строку 37 в вышеупомянутом пользовательском классе DQL для Cast:

        //old
        //$this->fieldIdentifierExpression = $parser->SimpleArithmeticExpression();
        //new
        $this->fieldIdentifierExpression = $parser->ComparisonExpression();

и как создать запрос:

$this->createQueryBuilder('a')
            ->select('a, (CAST(a.averageRating=:averageRating AS UNSIGNED) + CAST(a.author=:author AS UNSIGNED)) AS matches_count')
            ->setParameter('averageRating', $averageRating)
            ->setParameter('author', $author)
            ->orderBy('matches_count', 'DESC')
            ->getQuery()
            ->getResult();

и это похоже на то!

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

Чтобы повысить производительность позже, я планирую кэшировать 10 идентификаторов рекомендуемых статей для каждой отдельной страницы статьи в свою собственную таблицу. Так что не нужно делать расчеты при загрузке страницы. Этот стол можно воссоздавать каждые 24 часа с помощью cronjob.

ID | recommended_article_ids | article_id
1 | 10,24,76,88| 5

Отзывы и советы очень ценятся!

...