private function getSnippetsQuery(
        $locale,
        $type = null,
        $offset = null,
        $max = null,
        $search = null,
        $sortBy = null,
        $sortOrder = null
    ) {
        $snippetNode = $this->sessionManager->getSnippetNode($type);
        $workspace = $this->sessionManager->getSession()->getWorkspace();
        $queryManager = $workspace->getQueryManager();

        $qf = $queryManager->getQOMFactory();
        $qb = new QueryBuilder($qf);

        $qb->from(
            $qb->qomf()->selector('a', 'nt:unstructured')
        );

        if (null === $type) {
            $qb->where(
                $qb->qomf()->descendantNode('a', $snippetNode->getPath())
            );
        } else {
            $qb->where(
                $qb->qomf()->childNode('a', $snippetNode->getPath())
            );
        }

        $qb->andWhere(
            $qb->qomf()->comparison(
                $qb->qomf()->propertyValue('a', 'jcr:mixinTypes'),
                QueryObjectModelConstantsInterface::JCR_OPERATOR_EQUAL_TO,
                $qb->qomf()->literal('sulu:snippet')
            )
        );

        if (null !== $offset) {
            $qb->setFirstResult($offset);

            if (null === $max) {
                // we get zero results if no max specified
                throw new \InvalidArgumentException(
                    'If you specify an offset then you must also specify $max'
                );
            }

            $qb->setMaxResults($max);
        }

        if (null !== $search) {
            $search = str_replace('*', '%', $search);
            $searchConstraint = $qf->orConstraint(
                $qf->comparison(
                    $qf->propertyValue('a', 'i18n:' . $locale . '-title'),
                    QueryObjectModelConstantsInterface::JCR_OPERATOR_LIKE,
                    $qf->literal('%' . $search . '%')
                ),
                $qf->comparison(
                    $qf->propertyValue('a', 'template'),
                    QueryObjectModelConstantsInterface::JCR_OPERATOR_LIKE,
                    $qf->literal('%' . $search . '%')
                )
            );
            $qb->andWhere($searchConstraint);
        }

        // Title is a mandatory property for snippets
        // NOTE: Prefixing the language code and namespace here is bad. But the solution is
        //       refactoring (i.e. a node property name translator service).
        $sortOrder = (null !== $sortOrder ? strtoupper($sortOrder) : 'ASC');
        $sortBy = (null !== $sortBy ? $sortBy : 'title');

        $qb->orderBy(
            $qb->qomf()->propertyValue('a', 'i18n:' . $locale . '-' . $sortBy),
            null !== $sortOrder ? strtoupper($sortOrder) : 'ASC'
        );

        return $qb->getQuery();
    }