Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Deprecate getting query parts from QueryBuilder #6179

Merged
merged 1 commit into from Oct 10, 2023

Conversation

morozov
Copy link
Member

@morozov morozov commented Oct 10, 2023

Q A
Type deprecation

The methods were removed in #3836.

@morozov
Copy link
Member Author

morozov commented Oct 10, 2023

The DB2 builds are failing due to a 500: Internal Server Error from an IBM server. This is a known regularly happening issue.

@janklan
Copy link

janklan commented May 2, 2024

I have a use case where one of the class methods accepts a QueryBuilder instance that's meant to supply a query producing a list of IDs used in an article.tag_id IN ( subquery ) condition.

My application has various situation where the list of "tags in scope" is generated using vastly different logic, and I always end up running a query that fetches the same kind of data, but with varying result set, depending on what the result of the subquery is.

I wanted to ensure a correct Query Builder is passed by checking whether the SQL parts contain precisely one SELECT statement with a single property of a particular name. The name enforcement is a convention detail I can live without, but I do need the method to be supplied with a query producing a single-column result.

A realistic pseudo code of the use case might look like this:

class ArticleRepository
{
    public function __construct(private readonly EntityManagerInterface $entityManager) {}

    // This method allows the developer to pass a custom query builder object that should generate a sub query, whatever the logic may be - ArticleRepository is not (should not) be concerned with what the subquery internal logic is.
    public function getArticlesWithTagsInScopeQueryBuilder(QueryBuilder $tagScopeQueryBuilder): QueryBuilder
    {
        $baseQueryBuilder = $this->getBaseQueryBuilder();

        // Here is the key step that's now deprecated: ensuring the query won't fail. Again, an example to prove my point. The logic may be more complex than counting the number of select statements. 
        if (1 !== count($tagScopeQueryBuilder->getQueryPart('select'))) {
            throw new \InvalidArgumentException('The Tag Query Builder must be usable in a subquery, so it must yield a single column of Tags or Tag IDs.');
        }

        return $baseQueryBuilder
            ->andWhere(
                $baseQueryBuilder->expr()->in(
                    x: 'article.tag_id',
                    y: $tagScopeQueryBuilder->getSQL() // <------------- more likely to work, because if the subquery was not useful like this, we'd be able to reject it. 
                )
            );
    }

    private function getBaseQueryBuilder(): QueryBuilder
    {
        // IRL, this would be a fairly complex query fetching some additional entities etc.
        return $this->entityManager->createQueryBuilder()
            ->select('article')
            ->from(Article::class, 'article');
    }
}

and the usage might be, from anywhere else in the code:

$customQueryBuilder = $entityManager->getRepository(Tag::class)->createQueryBuilder()->select('tag.id');

$articleRepository->getArticlesWithTagsInScopeQueryBuilder(
    $customQueryBuilder
);

I found this PR through the deprecation notice in QueryBuilder::getQueryPart(), and I'm wondering whether there is any other way to check the contents of the query builder other than parsing the resulting SQL?


Update: greg0ire suggested I add a better piece of code to explain my intentions, so I did just that.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants