PHPackages                             surda/doctrine-queries - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Database &amp; ORM](/categories/database)
4. /
5. surda/doctrine-queries

ActiveLibrary[Database &amp; ORM](/categories/database)

surda/doctrine-queries
======================

Doctrine queries

v2.0.0(2y ago)0191MITPHPPHP &gt;=7.1

Since Nov 5Pushed 2y ago1 watchersCompare

[ Source](https://github.com/surda/doctrine-queries)[ Packagist](https://packagist.org/packages/surda/doctrine-queries)[ Docs](http://surani.cz)[ RSS](/packages/surda-doctrine-queries/feed)WikiDiscussions master Synced 2mo ago

READMEChangelogDependencies (8)Versions (4)Used By (0)

Doctrine queries
================

[](#doctrine-queries)

---

[![Build Status](https://camo.githubusercontent.com/41f84c3a2d1f589bf91e6f1443895489eee95e18e7516d3d69f8a6b641c86ddd/68747470733a2f2f7472617669732d63692e6f72672f73757264612f646f637472696e652d717565726965732e7376673f6272616e63683d6d6173746572)](https://travis-ci.org/surda/doctrine-queries)[![Licence](https://camo.githubusercontent.com/f3455b162186ebf435fa12489f8f6fb399eb58db4f970f21cd13da8c7484784c/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f6c2f73757264612f646f637472696e652d717565726965732e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/surda/doctrine-queries)[![Latest stable](https://camo.githubusercontent.com/7adf87ebea8b5792af148edd5f80be9bb9ae21c68e5a4a51e005b82fb4ce46ba/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f73757264612f646f637472696e652d717565726965732e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/surda/doctrine-queries)[![PHPStan](https://camo.githubusercontent.com/441b5874ce4df0a2defc892979c96c46889b69cb32119d04f0b48626349f8bc9/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5048505374616e2d656e61626c65642d627269676874677265656e2e7376673f7374796c653d666c6174)](https://github.com/phpstan/phpstan)

This repository is inspired by [Kdyby/Doctrine](https://github.com/Kdyby/Doctrine).

Installation
------------

[](#installation)

The recommended way to is via Composer:

```
composer require surda/doctrine-queries

```

Usage
-----

[](#usage)

### Entity repository

[](#entity-repository)

```
use Surda\Doctrine\Queries\QueryableRepository;

class UserRepository extends QueryableRepository
{
   // ...
}
```

### QueryObject

[](#queryobject)

```
use Doctrine\ORM;
use Surda\Doctrine\Queries\IQueryable;
use Surda\Doctrine\Queries\QueryObject;

class QuestionsQuery extends QueryObject
{
    /** @var array|\Closure[] */
    private $filter = [];

    /** @var array|\Closure[] */
    private $select = [];

    public function inCategory(Category $category = NULL)
    {
        $this->filter[] = function (QueryBuilder $qb) use ($category) {
            $qb->andWhere('q.category = :category')->setParameter('category', $category->getId());
        };
        return $this;
    }

    public function byUser($user)
    {
        if ($user instanceof Identity) {
            $user = $user->getUser();

        } elseif (!$user instanceof User) {
            throw new InvalidArgumentException;
        }

        $this->filter[] = function (QueryBuilder $qb) use ($user) {
            $qb->andWhere('u.id = :user')->setParameter('user', $user->getId());
        };
        return $this;
    }

    public function withLastPost()
    {
        $this->select[] = function (ORM\QueryBuilder $qb) {
            $qb->addSelect('partial lp.{id, createdAt}, partial lpa.{id}, partial lpau.{id, name}')
                ->leftJoin('q.lastPost', 'lp', Join::WITH, 'lp.spam = FALSE AND lp.deleted = FALSE')
                ->leftJoin('lp.author', 'lpa')
                ->leftJoin('lpa.user', 'lpau');
        };
        return $this;
    }

    public function withCategory()
    {
        $this->select[] = function (ORM\QueryBuilder $qb) {
            $qb->addSelect('c, pc')
                ->innerJoin('q.category', 'c')
                ->innerJoin('c.parent', 'pc');
        };
        return $this;
    }

    public function withAnswersCount()
    {
        $this->select[] = function (ORM\QueryBuilder $qb) {
            $subCount = $qb->getEntityManager()->createQueryBuilder()
                ->select('COUNT(a.id)')->from(Answer::class, 'a')
                ->andWhere('a.spam = FALSE AND a.deleted = FALSE')
                ->andWhere('a.question = q');

            $qb->addSelect("($subCount) AS answers_count");
        };
        return $this;
    }

    public function sortByPinned($order = 'ASC')
    {
        $this->select[] = function (ORM\QueryBuilder $qb) use ($order) {
            $qb->addSelect('FIELD(q.pinned, TRUE, FALSE) as HIDDEN isPinned');
            $qb->addOrderBy('isPinned', $order);
        };
        return $this;
    }

    public function sortByHasSolution($order = 'ASC')
    {
        $this->select[] = function (ORM\QueryBuilder $qb) use ($order) {
            $qb->addSelect('FIELD(IsNull(q.solution), TRUE, FALSE) as HIDDEN hasSolution');
            $qb->addOrderBy('hasSolution', $order);
        };
        return $this;
    }

    /**
     * @param IQueryable $repository
     * @return ORM\QueryBuilder
     */
    protected function doCreateQuery(IQueryable $repository)
    {
        $qb = $this->createBasicDql($repository)
            ->addSelect('partial i.{id}, partial u.{id, name}');

        foreach ($this->select as $modifier) {
            $modifier($qb);
        }

        return $qb->addOrderBy('q.createdAt', 'DESC');
    }

    /**
     * @param IQueryable $repository
     * @return ORM\QueryBuilder
     */
    protected function doCreateCountQuery(IQueryable $repository)
    {
        return $this->createBasicDql($repository)->select('COUNT(q.id)');
    }

    /**
     * @param IQueryable $repository
     * @return ORM\QueryBuilder
     */
    private function createBasicDql(IQueryable $repository)
    {
        $qb = $repository->createQueryBuilder()
            ->select('q')->from(Question::class, 'q')
            ->andWhere('q.spam = FALSE AND q.deleted = FALSE')
            ->innerJoin('q.author', 'i')
            ->innerJoin('i.user', 'u');

        foreach ($this->filter as $modifier) {
            $modifier($qb);
        }

        return $qb;
    }
}
```

```
$query = (new QuestionsQuery())
	->withLastPost()
	->byUser($user);

$result = $repository->fetch($query);
```

### ResultSet

[](#resultset)

```
class Repository extends \Surda\Doctrine\Queries\EntityRepository
{
    /**
     * @return \Surda\Doctrine\Queries\ResultSet
     */
    public function getResultSet(): \Surda\Doctrine\Queries\ResultSet
    {
        $query = $this->createQueryBuilder('q')->addOrderBy('q.id', 'DESC')->getQuery();

        return new \Surda\Doctrine\Queries\ResultSet($query);
    }
}
```

### Presenter

[](#presenter)

```
$visualPaginator = $this['vp'];
$paginator = $visualPaginator->getPaginator();
$paginator->setItemsPerPage(20);

$resultSet = $this->repository->getResultSet();
$resultSet->applyPaginator($paginator);

foreach ($resultSet as $entity) {
	// ...
}
```

###  Health Score

25

—

LowBetter than 37% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity7

Limited adoption so far

Community8

Small or concentrated contributor base

Maturity54

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~750 days

Total

3

Last Release

877d ago

Major Versions

v1.1.0 → v2.0.02023-12-14

### Community

Maintainers

![](https://www.gravatar.com/avatar/e8d497ef90ca9ed180419b5ab29857be10e88d0614cf01c94b0f2ab5094de45d?d=identicon)[surda](/maintainers/surda)

---

Top Contributors

[![surda](https://avatars.githubusercontent.com/u/588663?v=4)](https://github.com/surda "surda (9 commits)")

---

Tags

nettedoctrine

###  Code Quality

Static AnalysisPHPStan

Type Coverage Yes

### Embed Badge

![Health badge](/badges/surda-doctrine-queries/health.svg)

```
[![Health](https://phpackages.com/badges/surda-doctrine-queries/health.svg)](https://phpackages.com/packages/surda-doctrine-queries)
```

###  Alternatives

[kdyby/doctrine

Doctrine integration into Nette Framework

1091.0M86](/packages/kdyby-doctrine)[nettrine/orm

Doctrine ORM for Nette Framework

581.9M37](/packages/nettrine-orm)[nettrine/fixtures

Doctrine Fixtures for Nette Framework

181.2M8](/packages/nettrine-fixtures)[kdyby/doctrine-cache

Doctrine Cache bridge for Nette Framework

101.3M19](/packages/kdyby-doctrine-cache)[kdyby/annotations

Doctrine Annotations integration into Nette Framework

101.3M18](/packages/kdyby-annotations)[nettrine/extensions-atlantic18

Doctrine2 behavioral extensions for Nette Framework

12922.2k3](/packages/nettrine-extensions-atlantic18)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
