PHPackages                             algoritma/shopware-query-builder - 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. algoritma/shopware-query-builder

ActiveShopware-platform-plugin[Database &amp; ORM](/categories/database)

algoritma/shopware-query-builder
================================

A modern, fluent query builder for Shopware 6.7+ with zero configuration. Write intuitive SQL-like queries with automatic validation, alias support, and type safety for cleaner code.

1.0.0(2mo ago)5180↓50%MITPHPPHP ^8.2CI passing

Since Mar 4Pushed 1mo agoCompare

[ Source](https://github.com/algoritma-dev/shopware-query-builder)[ Packagist](https://packagist.org/packages/algoritma/shopware-query-builder)[ RSS](/packages/algoritma-shopware-query-builder/feed)WikiDiscussions main Synced 1mo ago

READMEChangelog (1)Dependencies (5)Versions (2)Used By (0)

Shopware Query Builder - Fluent API for Shopware 6.7
====================================================

[](#shopware-query-builder---fluent-api-for-shopware-67)

A modern and intuitive library for building Shopware 6.7 queries with fluent syntax, alias support, and zero configuration.

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

[](#quick-start)

```
use Shopware\Core\Content\Product\ProductEntity;

// Simple query
$products = sw_query(ProductEntity::class)
    ->where('active = true')
    ->where('stock > 0')
    ->get();

// Query with aliases and associations
$products = sw_query(ProductEntity::class, 'p')
    ->with('manufacturer', 'm')
    ->with('categories', 'c')
    ->where('p.active = true')
    ->where('m.active = true')
    ->where('c.visible = true')
    ->orderBy('p.name', 'ASC')
    ->limit(20)
    ->getEntities();

// Get single entity
$product = sw_query(ProductEntity::class)
    ->where('id = ' . $productId)
    ->firstOrFail();

// Check existence
$exists = sw_query(ProductEntity::class)
    ->where('productNumber = "SW-001"')
    ->exists();

// Pagination
$pagination = sw_query(ProductEntity::class, 'p')
    ->with('manufacturer', 'm')
    ->where('p.active = true')
    ->where('m.active = true')
    ->paginate(1, 20)
    ->getPaginated();
```

Features
--------

[](#features)

### Zero Configuration

[](#zero-configuration)

- No manual mapping required
- Directly uses Shopware's `EntityDefinition`
- Always synchronized with Definitions
- Automatic validation of properties and associations

### Advanced Features

[](#advanced-features)

- **Parameter Binding**: `setParameter()`, `setParameters()` for secure queries
- **Aggregations**: `addCount()`, `addSum()`, `addAvg()`, `addMin()`, `addMax()`
- **Nested Groups**: `whereGroup()`, `orWhereGroup()` with infinite nesting
- **Reusable Scopes**: `scope()`, `scopes()` for query logic reuse
- **Soft Deletes**: `withTrashed()`, `onlyTrashed()`, `withoutTrashed()`
- **Query Debugging**: `debug()`, `dump()`, `dd()`, `toDebugArray()`

### Aliases for Linear Queries

[](#aliases-for-linear-queries)

```
// With aliases - Linear and clear!
sw_query(ProductEntity::class, 'p')
    ->with('manufacturer', 'm')
    ->where('p.active = true')
    ->where('m.active = true')
    ->orderBy('m.name', 'ASC')

// Without aliases - Complex nesting
sw_query(ProductEntity::class)
    ->where('active = true')
    ->with('manufacturer', fn($q) =>
        $q->where('active = true')
    )
```

### Integrated Execution

[](#integrated-execution)

```
->get()              // EntitySearchResult complete
->getEntities()      // Only EntityCollection
->toArray()          // Array of entities
->getIds()           // IdSearchResult
->getIdsArray()      // Array of IDs
->getOneOrNull()     // First entity or null
->getOneOrThrow()    // First entity or exception
->first()            // Alias of getOneOrNull
->firstOrFail()      // Alias of getOneOrThrow
->count()            // Count results
->exists()           // Check existence
->doesntExist()      // Check non-existence
->getPaginated()     // Formatted pagination array
```

### Advanced Query Methods

[](#advanced-query-methods)

```
// Raw SQL-like expressions
->where('field = value')                      // Equals
->where('field > 10')                         // Greater than
->where('stock > 10 AND active = true')       // Compound AND (auto-creates GroupExpression)
->where('featured = true OR promoted = true') // Compound OR (auto-creates GroupExpression)

// Parameter binding (secure, reusable)
->where('status = :status')                   // Named parameter
->setParameter('status', 'active')            // Set single parameter
->setParameters(['status' => 'active'])       // Set multiple parameters

// Convenience methods (unchanged)
->whereBetween('field', 10, 100)    // Between values
->whereIn('field', [1, 2, 3])       // In array
->whereNotIn('field', [1, 2])       // Not in array
->whereNull('field')                // Is null
->whereNotNull('field')             // Is not null
->whereStartsWith('field', 'prefix')// Starts with
->whereEndsWith('field', 'suffix')  // Ends with

// Aggregations
->addCount('name')                  // Count aggregation
->addSum('field', 'name')           // Sum aggregation
->addAvg('field', 'name')           // Average aggregation
->addMin('field', 'name')           // Minimum aggregation
->addMax('field', 'name')           // Maximum aggregation

// Grouping
->whereGroup(fn($q) => ...)         // Group conditions with AND
->orWhereGroup(fn($q) => ...)       // Group conditions with OR

// Scopes
->scope(ScopeInterface $scope)      // Apply single scope
->scopes(array $scopes)             // Apply multiple scopes

// Soft Deletes
->withTrashed()                     // Include soft-deleted
->onlyTrashed()                     // Only soft-deleted
->withoutTrashed()                  // Exclude soft-deleted (default)

// Debugging
->debug()                           // Enable debug mode
->dump()                            // Dump and continue
->dd()                              // Dump and die
->toDebugArray()                    // Get query as array
```

### Type Safety and Validation

[](#type-safety-and-validation)

```
// Automatic validation with helpful messages
try {
    sw_query(ProductEntity::class)
        ->where('invalidProperty = true');
} catch (InvalidPropertyException $e) {
    // "Property 'invalidProperty' does not exist on ProductEntity.
    //  Available properties: id, name, productNumber, stock, ..."
}
```

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

[](#installation)

```
composer require yourvendor/shopware-query-builder
```

Documentation
-------------

[](#documentation)

### Main Documents

[](#main-documents)

- **[AGENTS.md](AGENTS.md)** - Complete project documentation
    - Architecture
    - Components
    - Implementation
    - Best Practices
    - Complete API Reference

Examples
--------

[](#examples)

### Example 1: Product List

[](#example-1-product-list)

```
#[Route('/products')]
public function list(Request $request): Response
{
    $pagination = sw_query(ProductEntity::class, 'p')
        ->with('manufacturer', 'm')
        ->with('cover.media')
        ->where('p.active = true')
        ->where('p.stock > 0')
        ->where('m.active = true')
        ->orderBy('p.name', 'ASC')
        ->paginate($request->query->getInt('page', 1), 20)
        ->getPaginated();

    return $this->render('products.html.twig', $pagination);
}
```

### Example 2: Product Detail

[](#example-2-product-detail)

```
#[Route('/product/{id}')]
public function detail(string $id): Response
{
    try {
        $product = sw_query(ProductEntity::class)
            ->where('id = "' . $id . '"')
            ->where('active = true')
            ->with('manufacturer')
            ->with('categories', 'c')
            ->where('c.visible = true')
            ->with('media.media')
            ->firstOrFail();
    } catch (EntityNotFoundException $e) {
        throw $this->createNotFoundException();
    }

    return $this->render('product.html.twig', ['product' => $product]);
}
```

### Example 3: Search

[](#example-3-search)

```
#[Route('/search')]
public function search(Request $request): Response
{
    $term = $request->query->get('q');

    $products = sw_query(ProductEntity::class, 'p')
        ->with('manufacturer', 'm')
        ->where('p.active = true')
        ->where('p.name LIKE "' . $term . '"')
        ->orWhere(function($q) use ($term) {
            $q->where('description LIKE "' . $term . '"') // LIKE operator doesn't need %, Shopware ContainsFilter adds it automatically
              ->where('productNumber LIKE "' . $term . '"');
        })
        ->orderBy('p.name', 'ASC')
        ->limit(50)
        ->getEntities();

    return $this->render('search.html.twig', ['products' => $products]);
}
```

### Example 4: Complex Filters

[](#example-4-complex-filters)

```
$products = sw_query(ProductEntity::class, 'p')
    ->with('manufacturer', 'm')
    ->with('categories', 'c')
    ->with('tax', 't')
    ->where('p.active = true')
    ->whereBetween('p.price', $minPrice, $maxPrice)
    ->where('p.stock > 0')
    ->where('m.active = true')
    ->whereIn('m.country', ['DE', 'AT', 'CH'])
    ->whereIn('c.id', $categoryIds)
    ->where('t.taxRate  0')
          ->orWhereGroup(function($nested) {
              $nested->where('availableStock > 0');
          });
    })
    ->whereGroup(function($q) {
        // AND (price >= 10 AND price where('price >= 10')
          ->where('price  :minStock')
    ->setParameters([
        'active' => true,
        'minStock' => 10
    ])
    ->getEntities();

// Parameters with IN operator
$products = sw_query(ProductEntity::class)
    ->where('status IN (:statuses)')
    ->setParameter('statuses', ['active', 'pending', 'processing'])
    ->getEntities();

// Range queries with parameters
$products = sw_query(ProductEntity::class)
    ->where('price >= :minPrice AND price  :minStock');

// Execute with different parameter sets
$activeProducts = $queryTemplate
    ->setParameters(['active' => true, 'minStock' => 10])
    ->getEntities();

// Complex example with multiple parameter types
$products = sw_query(ProductEntity::class, 'p')
    ->with('manufacturer', 'm')
    ->where('p.active = :active')
    ->where('p.stock >= :minStock AND p.stock = :minPrice')
    ->orWhere('p.featured = :featured')
    ->setParameters([
        'active' => true,
        'minStock' => 10,
        'maxStock' => 100,
        'countries' => ['DE', 'AT', 'CH'],
        'minPrice' => 50,
        'featured' => true
    ])
    ->orderBy('p.name', 'ASC')
    ->getEntities();
```

### Example 10: Query Debugging

[](#example-10-query-debugging)

```
// Enable debug mode
$products = sw_query(ProductEntity::class, 'p')
    ->with('manufacturer', 'm')
    ->where('p.active = true')
    ->where('m.active = true')
    ->debug() // Will print query info on execution
    ->getEntities();

// Dump query info and continue
sw_query(ProductEntity::class)
    ->where('active = true')
    ->orderBy('name')
    ->dump() // Prints query structure
    ->getEntities();

// Dump and die (like dd() in Laravel)
sw_query(ProductEntity::class)
    ->where('active = true')
    ->dd(); // Prints and exits

// Get query as array for inspection
$debugInfo = sw_query(ProductEntity::class, 'p')
    ->where('p.active = true')
    ->limit(10)
    ->toDebugArray();
// Returns: ['entity' => '...', 'where' => [...], 'limit' => 10, ...]
```

### Example 11: Updates

[](#example-11-updates)

```
// Update with conditions and get updated entities
$products = sw_query(ProductEntity::class, 'p')
    ->where('p.active = true')
    ->update([/** data **/]); // Will return entities objects with updated data *NOTICE: flat associative array for updates with conditions*

// Update without conditions (Shopware repository update standard behavior) and get entity objects with updated data
sw_query(ProductEntity::class)
    ->update(
        [[ /** data **/]]
    );
```

Migration Guide v2.x → v3.0.0
-----------------------------

[](#migration-guide-v2x--v300)

\###️ BREAKING CHANGES

Version 3.0.0 introduces a completely new WHERE clause syntax for improved readability and intuitive SQL-like expressions.

### What Changed

[](#what-changed)

**OLD Syntax (v2.x):**

```
->where('field', 'operator', 'value')  // 3 parameters
->where('stock', '>', 10)
->where('active', true)
```

**NEW Syntax (v3.0.0):**

```
->where('field operator value')  // 1 parameter, raw SQL-like
->where('stock > 10')
->where('active = true')
```

### Migration Steps

[](#migration-steps)

1. **Simple Equality:**

    ```
    // Before
    ->where('active', true)

    // After
    ->where('active = true')
    ```
2. **Comparison Operators:**

    ```
    // Before
    ->where('stock', '>', 10)
    ->where('price', '>=', 100)

    // After
    ->where('stock > 10')
    ->where('price >= 100')
    ```
3. **String Values (add quotes):**

    ```
    // Before
    ->where('status', 'active')

    // After
    ->where('status = "active"')
    // or
    ->where('status = active')  // unquoted also works
    ```
4. **Compound Expressions (Auto-Grouping):**

    ```
    // Before
    ->whereGroup(fn($q) =>
        $q->where('stock', '>', 10)
          ->where('active', true)
    )

    // After (much simpler!)
    ->where('stock > 10 AND active = true')
    ```
5. **OR Logic:**

    ```
    // Before
    ->orWhere(fn($q) =>
        $q->where('featured', true)
          ->where('promoted', true)
    )

    // After
    ->where('featured = true OR promoted = true')
    ```

### Convenience Methods (Still Work!)

[](#convenience-methods-still-work)

The following convenience methods still work as before:

- `whereIn($field, $array)` - unchanged
- `whereNotIn($field, $array)` - unchanged
- `whereNull($field)` - unchanged
- `whereNotNull($field)` - unchanged
- `whereBetween($field, $min, $max)` - unchanged
- `whereStartsWith($field, $value)` - unchanged
- `whereEndsWith($field, $value)` - unchanged

🔧 Configuration
---------------

[](#-configuration)

### 1. Register services in `services.xml`

[](#1-register-services-in-servicesxml)

```

```

### 2. Register helper in `composer.json`

[](#2-register-helper-in-composerjson)

```
{
    "autoload": {
        "psr-4": {
            "YourVendor\\QueryBuilder\\": "src/"
        },
        "files": [
            "src/helpers.php"
        ]
    }
}
```

Best Practices
--------------

[](#best-practices)

### 1. Use aliases for clear queries

[](#1-use-aliases-for-clear-queries)

```
// Clear which field belongs to which entity
sw_query(ProductEntity::class, 'p')
    ->with('manufacturer', 'm')
    ->where('p.active = true')
    ->where('m.active = true')
```

### 2. Register associations before using the alias

[](#2-register-associations-before-using-the-alias)

```
// Correct
->with('manufacturer', 'm')  // Register first
->where('m.active = true')   // Then use

// Error
->where('m.active = true')   // Alias not registered!
->with('manufacturer', 'm')
```

### 3. Use callbacks for complex OR

[](#3-use-callbacks-for-complex-or)

```
// Use aliases for simple filters
->with('manufacturer', 'm')
->where('m.active = true')

// Use callbacks for OR logic
->with('categories', function($q) {
    $q->where('visible = true')
      ->orWhere('featured = true');
})
```

### 4. Handle exceptions for getOneOrThrow

[](#4-handle-exceptions-for-getoneorthrow)

```
try {
    $product = sw_query(ProductEntity::class)
        ->where('id = "' . $id . '"')
        ->getOneOrThrow();
} catch (EntityNotFoundException $e) {
    // Handle not found
}
```

### 5. Use parameter binding for dynamic values

[](#5-use-parameter-binding-for-dynamic-values)

```
// Secure - Uses parameter binding
$products = sw_query(ProductEntity::class)
    ->where('status = :status')
    ->setParameter('status', $userInput)
    ->getEntities();

// Also secure - QueryBuilder handles values safely
$products = sw_query(ProductEntity::class)
    ->where('status = "' . $userInput . '"')
    ->getEntities();
```

### 6. Use exists() for checks

[](#6-use-exists-for-checks)

```
// More efficient
if (sw_query(ProductEntity::class)->where('id = "' . $id . '"')->exists()) {
    // ...
}

// Less efficient
if (sw_query(ProductEntity::class)->where('id = "' . $id . '"')->count() > 0) {
    // ...
}
```

Advantages
----------

[](#advantages)

### vs Native Criteria

[](#vs-native-criteria)

```
// Shopware Criteria (verbose)
$criteria = new Criteria();
$criteria->addFilter(new EqualsFilter('active', true));
$criteria->addFilter(new RangeFilter('stock', [RangeFilter::GT => 0]));
$criteria->addAssociation('manufacturer');
$criteria->getAssociation('manufacturer')
    ->addFilter(new EqualsFilter('active', true));
$result = $repository->search($criteria, $context);

// Query Builder (intuitive)
$result = sw_query(ProductEntity::class, 'p')
    ->with('manufacturer', 'm')
    ->where('p.active = true')
    ->where('p.stock > 0')
    ->where('m.active = true')
    ->get();
```

### vs Doctrine QueryBuilder

[](#vs-doctrine-querybuilder)

```
// Doctrine-like syntax for Shopware!
sw_query(ProductEntity::class, 'p')
    ->with('manufacturer', 'm')
    ->where('p.active = true')
    ->where('m.country = "DE"')
    ->orderBy('p.name', 'ASC')
    ->limit(20)
    ->getEntities();
```

Performance
-----------

[](#performance)

- **Zero overhead**: Compiled to `Criteria` identical
- **Runtime validation**: Errors before execution
- **Caching**: EntityDefinition cached in memory
- **Lazy loading**: Repository resolved on-demand
- **Efficient aggregations**: Native Shopware aggregation support
- **Optimized grouping**: Recursive compilation to MultiFilter

Testing
-------

[](#testing)

The library includes comprehensive test coverage:

- **156 Unit Tests** - 100% of core functionality tested
- **311 Assertions** - Extensive validation
- **PHPStan Level 6** - Maximum type safety
- **Zero Errors** - All tests passing

Run tests:

```
docker run --rm -u 1000 -v .:/app -w /app composer ./vendor/bin/phpunit
```

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

[](#contributing)

Contributions welcome! See [AGENTS.md](AGENTS.md) for architectural details.

License
-------

[](#license)

MIT

Credits
-------

[](#credits)

Developed for Shopware 6.7+ with focus on:

- Developer Experience
- Type Safety
- Zero Configuration
- Modern PHP 8.2+

---

###  Health Score

43

—

FairBetter than 91% of packages

Maintenance87

Actively maintained with recent releases

Popularity20

Limited adoption so far

Community7

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

Unknown

Total

1

Last Release

75d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/470d7f2b64c268ccd0d73d1d19da604f5049ffdc717170df28ac460d34b8a327?d=identicon)[raffaelecarelle](/maintainers/raffaelecarelle)

![](https://www.gravatar.com/avatar/117803c0597726db044b29864f1943dcb8b63f286eb26ff36bd5b4f132b4a6ef?d=identicon)[develop-algoritma](/maintainers/develop-algoritma)

---

Top Contributors

[![raffaelecarelle](https://avatars.githubusercontent.com/u/15015792?v=4)](https://github.com/raffaelecarelle "raffaelecarelle (49 commits)")

---

Tags

shopwarefluentquery builderdalshopware6

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/algoritma-shopware-query-builder/health.svg)

```
[![Health](https://phpackages.com/badges/algoritma-shopware-query-builder/health.svg)](https://phpackages.com/packages/algoritma-shopware-query-builder)
```

###  Alternatives

[j4mie/idiorm

A lightweight nearly-zero-configuration object-relational mapper and fluent query builder for PHP5

2.0k1.5M29](/packages/j4mie-idiorm)[cycle/orm

PHP DataMapper ORM and Data Modelling Engine

1.3k835.4k65](/packages/cycle-orm)[usmanhalalit/pixie

A lightweight, expressive, framework agnostic query builder for PHP.

6872.2M15](/packages/usmanhalalit-pixie)[envms/fluentpdo

FluentPDO is a quick and light PHP library for rapid query building. It features a smart join builder, which automatically creates table joins.

925511.7k13](/packages/envms-fluentpdo)[foolz/sphinxql-query-builder

A PHP query builder for SphinxQL and ManticoreQL with MySQLi and PDO drivers.

3232.2M32](/packages/foolz-sphinxql-query-builder)[lulco/phoenix

Database Migrations for PHP

180329.4k4](/packages/lulco-phoenix)

PHPackages © 2026

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