PHPackages                             shredio/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. shredio/doctrine-queries

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

shredio/doctrine-queries
========================

v0.11.0(10mo ago)0355↓100%1MITPHPPHP &gt;=8.3CI passing

Since Jun 16Pushed 5mo agoCompare

[ Source](https://github.com/Shredio/doctrine-queries)[ Packagist](https://packagist.org/packages/shredio/doctrine-queries)[ RSS](/packages/shredio-doctrine-queries/feed)WikiDiscussions master Synced 1mo ago

READMEChangelog (6)Dependencies (7)Versions (8)Used By (1)

Doctrine Queries
================

[](#doctrine-queries)

A simplified and type-safe PHP library for Doctrine ORM that provides an intuitive interface for database queries with automatic query building, result handling, and PHPStan integration.

Features
--------

[](#features)

- **Simple and intuitive API** for common database operations
- **Type-safe queries** with full PHPStan support
- **Multiple result formats** - objects, arrays, or scalar values
- **Flexible criteria system** with support for operators, null values, and arrays
- **Automatic query optimization** and result hydration
- **Memory-efficient iteration** for large datasets
- **Built-in PHPStan extensions** for static analysis

Requirements
------------

[](#requirements)

- PHP 8.3 or higher
- Doctrine ORM 3.2 or higher

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

[](#installation)

```
composer require shredio/doctrine-queries
```

Quick Start
-----------

[](#quick-start)

```
use Shredio\DoctrineQueries\DoctrineQueries;

// Initialize with Doctrine's ManagerRegistry
$queries = new DoctrineQueries($managerRegistry);

// Query entities as objects
$users = $queries->objects->findBy(User::class, ['status' => 'active'])->asArray();

// Query as associative arrays (faster hydration)
$userData = $queries->arrays->findBy(User::class, ['age >' => 18])->asArray();

// Query scalar values only
$userNames = $queries->scalars->findColumnValuesBy(User::class, 'name', ['status' => 'active'])->asArray();

// Use subqueries for complex filtering
$activeUsersWithPosts = $queries->objects->findBy(
    User::class,
    [
        'id' => $queries->subQuery(
            Post::class,
            ['status' => 'published'],
            select: ['author.id']
        )
    ]
)->asArray();

// Check if entities exist
$hasActiveUsers = $queries->existsBy(User::class, ['status' => 'active']);

// Count entities
$activeUserCount = $queries->countBy(User::class, ['status' => 'active']);

// Delete entities
$deletedCount = $queries->deleteBy(User::class, ['status' => 'inactive']);
```

Query Types
-----------

[](#query-types)

### Object Queries

[](#object-queries)

Returns full entity objects with all relationships loaded:

```
$users = $queries->objects->findBy(User::class, ['status' => 'active'])->asArray();
// Returns: User[]
```

### Array Queries

[](#array-queries)

Returns associative arrays (faster hydration, less memory usage):

```
$users = $queries->arrays->findBy(User::class, ['status' => 'active'])->asArray();
// Returns: array[]

// With field selection
$users = $queries->arrays->findBy(User::class, ['status' => 'active'], select: ['id', 'name'])->asArray();
// Returns: [['id' => 1, 'name' => 'John'], ...]

// With join configuration for optimal performance
$posts = $queries->arrays->findBy(
    Post::class,
    ['status' => 'published'],
    select: ['title', 'author.name'],
    joinConfig: ['author' => 'inner'] // Use inner join for better performance
)->asArray();
```

### Scalar Queries

[](#scalar-queries)

Returns primitive values only:

```
$userNames = $queries->scalars->findColumnValuesBy(User::class, 'name')->asArray();
// Returns: string[]

$userName = $queries->scalars->findSingleColumnValueBy(User::class, 'name', ['id' => 1]);
// Returns: string|null
```

Criteria System
---------------

[](#criteria-system)

The library supports a flexible criteria system with various operators:

### Basic Equality

[](#basic-equality)

```
// Equals
['name' => 'John']
['id' => 42]

// Explicit equals
['name =' => 'John']
```

### Comparison Operators

[](#comparison-operators)

```
// Not equals
['status !=' => 'inactive']

// Greater than
['age >' => 18]

// Greater than or equal
['age >=' => 18]

// Less than
['score ' => 18,
    'status' => 'active',
    'city' => ['Prague', 'Brno'],
    'deleted_at' => null
];
```

Sorting
-------

[](#sorting)

```
$users = $queries->arrays->findBy(
    User::class,
    ['status' => 'active'],
    orderBy: ['created_at' => 'DESC', 'name' => 'ASC']
)->asArray();
```

Field Selection
---------------

[](#field-selection)

```
// Select specific fields
$users = $queries->arrays->findBy(
    User::class,
    ['status' => 'active'],
    select: ['id', 'name', 'email']
)->asArray();

// Field aliasing
$users = $queries->arrays->findBy(
    User::class,
    ['status' => 'active'],
    select: ['id' => 'userId', 'name' => 'fullName']
)->asArray();

// Select related fields with automatic joins
$posts = $queries->arrays->findBy(
    Post::class,
    ['status' => 'published'],
    select: ['title', 'author.name', 'category.name']
)->asArray();

// Select all fields (without relations)
$posts = $queries->arrays->findBy(
    Post::class,
    ['status' => 'published'],
    select: ['*'] // Selects all fields
)->asArray();

// Select all fields including relations
$posts = $queries->arrays->findBy(
    Post::class,
    ['status' => 'published'],
    select: ['**'] // Selects all fields including ManyToOne relations
)->asArray();
```

Working with Results
--------------------

[](#working-with-results)

### Arrays

[](#arrays)

```
$users = $queries->arrays->findBy(User::class)->asArray();
foreach ($users as $user) {
    echo $user['name'];
}
```

### Memory-Efficient Iteration

[](#memory-efficient-iteration)

For large datasets, use yielding to avoid loading everything into memory:

```
foreach ($queries->arrays->findBy(User::class)->yield() as $user) {
    // Process one user at a time
    processUser($user);
}
```

### Key-Value Pairs

[](#key-value-pairs)

```
// Get id => name pairs
$userOptions = $queries->arrays->findPairsBy(User::class, 'id', 'name')->asArray();
// Returns: [1 => 'John', 2 => 'Jane', ...]
```

### Column Values

[](#column-values)

```
// Get all unique email domains
$domains = $queries->scalars->findColumnValuesBy(
    User::class,
    'email_domain',
    distinct: true
)->asArray();
```

Advanced Features
-----------------

[](#advanced-features)

### Subqueries

[](#subqueries)

Use subqueries for complex filtering and data retrieval:

```
// Find users who have published posts
$usersWithPosts = $queries->objects->findBy(
    User::class,
    [
        'id' => $queries->subQuery(
            Post::class,
            ['status' => 'published'],
            select: ['author.id']
        )
    ]
)->asArray();

// Find posts by users from specific cities
$posts = $queries->arrays->findBy(
    Post::class,
    [
        'author.id' => $queries->subQuery(
            User::class,
            ['city' => ['Prague', 'Brno']],
            select: ['id']
        )
    ]
)->asArray();
```

### Join Configuration

[](#join-configuration)

Control join types for optimal query performance:

```
// Use inner joins for better performance when you know relations exist
$posts = $queries->arrays->findBy(
    Post::class,
    ['author.status' => 'active'],
    select: ['title', 'author.name'],
    joinConfig: [
        'author' => 'inner' // Inner join for author relation
    ]
)->asArray();

// Mix of inner and left joins
$comments = $queries->arrays->findBy(
    Comment::class,
    [],
    select: ['content', 'author.name', 'post.title'],
    joinConfig: [
        'author' => 'left',  // Left join (author might be null)
        'post' => 'inner'    // Inner join (comment must have a post)
    ]
)->asArray();
```

Counting and Existence
----------------------

[](#counting-and-existence)

```
// Count entities
$activeUsers = $queries->countBy(User::class, ['status' => 'active']);

// Check existence
$hasAdmins = $queries->existsBy(User::class, ['role' => 'admin']);

// Count with complex criteria
$recentActiveUsers = $queries->countBy(User::class, [
    'status' => 'active',
    'last_login >' => new DateTime('-30 days')
]);

// Count specific field values
$uniqueEmails = $queries->countBy(User::class, [], field: 'email', distinct: true);

// Count with join configuration
$postsWithActiveAuthors = $queries->countBy(
    Post::class,
    ['author.status' => 'active'],
    joinConfig: ['author' => 'left']
);
```

Deletion Operations
-------------------

[](#deletion-operations)

```
// Delete entities by criteria
$deletedCount = $queries->deleteBy(User::class, ['status' => 'inactive']);

// Delete with complex criteria
$deletedOldUsers = $queries->deleteBy(User::class, [
    'last_login arrays->findBy(
    User::class,
    ['status' => 'active'],
    orderBy: ['created_at' => 'DESC'],
    select: ['id', 'name', 'email', 'created_at']
)->asArray();

// Get user count by status
$statusCounts = [];
foreach (['active', 'inactive', 'banned'] as $status) {
    $statusCounts[$status] = $queries->countBy(User::class, ['status' => $status]);
}

// Get recent user emails for newsletter
$recentEmails = $queries->scalars->findColumnValuesBy(
    User::class,
    'email',
    ['created_at >' => new DateTime('-7 days')]
)->asArray();
```

### Content Management

[](#content-management)

```
// Get published articles with author info using modern field path selection
$articles = $queries->arrays->findBy(
    Article::class,
    [
        'status' => 'published',
        'published_at ' => 0,
        'status' => 'active',
        'category.name' => ['Electronics', 'Books']
    ],
    orderBy: ['price' => 'ASC'],
    select: ['id', 'name', 'price', 'stock_quantity', 'category.name'],
    joinConfig: ['category' => 'inner']
)->asArray();

// Get products with recent orders using subqueries
$popularProducts = $queries->arrays->findBy(
    Product::class,
    [
        'id' => $queries->subQuery(
            OrderItem::class,
            ['order.created_at >' => new DateTime('-30 days')],
            select: ['product.id']
        )
    ],
    select: ['name', 'price']
)->asArray();

// Get order statistics
$orderStats = [
    'total' => $queries->countBy(Order::class),
    'pending' => $queries->countBy(Order::class, ['status' => 'pending']),
    'completed' => $queries->countBy(Order::class, ['status' => 'completed'])
];
```

Testing
-------

[](#testing)

```
composer test
```

Static Analysis
---------------

[](#static-analysis)

```
composer phpstan
```

License
-------

[](#license)

MIT License. See [LICENSE](LICENSE) file for details.

Contributing
------------

[](#contributing)

1. Fork the repository
2. Create a feature branch
3. Make your changes
4. Add tests for new functionality
5. Ensure all tests pass
6. Submit a pull request

Changelog
---------

[](#changelog)

See [releases](https://github.com/shredio/doctrine-queries/releases) for version history and changes.

###  Health Score

35

—

LowBetter than 80% of packages

Maintenance64

Regular maintenance activity

Popularity14

Limited adoption so far

Community8

Small or concentrated contributor base

Maturity46

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 ~3 days

Total

6

Last Release

314d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/312e788a47a251e05734378921d4596a91819b7de416fa18e77aa69e08798ea8?d=identicon)[Antik](/maintainers/Antik)

---

Top Contributors

[![MartkCz](https://avatars.githubusercontent.com/u/10145362?v=4)](https://github.com/MartkCz "MartkCz (50 commits)")

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Type Coverage Yes

### Embed Badge

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

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

###  Alternatives

[scienta/doctrine-json-functions

A set of extensions to Doctrine that add support for json query functions.

58523.9M35](/packages/scienta-doctrine-json-functions)[damienharper/auditor-bundle

Integrate auditor library in your Symfony projects.

4542.8M](/packages/damienharper-auditor-bundle)[sonata-project/entity-audit-bundle

Audit for Doctrine Entities

644989.8k1](/packages/sonata-project-entity-audit-bundle)[pixelfederation/doctrine-resettable-em-bundle

Symfony bundle for decorating default entity managers using a resettable decorator.

20113.5k](/packages/pixelfederation-doctrine-resettable-em-bundle)[rcsofttech/audit-trail-bundle

Enterprise-grade, high-performance Symfony audit trail bundle. Automatically track Doctrine entity changes with split-phase architecture, multiple transports (HTTP, Queue, Doctrine), and sensitive data masking.

1022.4k](/packages/rcsofttech-audit-trail-bundle)[ahmed-bhs/doctrine-doctor

Runtime analysis tool for Doctrine ORM integrated into Symfony Web Profiler. Unlike static linters, it analyzes actual query execution at runtime to detect performance bottlenecks, security vulnerabilities, and best practice violations during development with real execution context and data.

813.1k](/packages/ahmed-bhs-doctrine-doctor)

PHPackages © 2026

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