PHPackages                             concept-labs/dbal - 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. concept-labs/dbal

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

concept-labs/dbal
=================

(C)oncept-Labs DBAL

1.0.2(6mo ago)026[1 PRs](https://github.com/Concept-Labs/dbal/pulls)3Apache-2.0PHPPHP &gt;=8.2

Since Nov 17Pushed 6mo ago1 watchersCompare

[ Source](https://github.com/Concept-Labs/dbal)[ Packagist](https://packagist.org/packages/concept-labs/dbal)[ RSS](/packages/concept-labs-dbal/feed)WikiDiscussions main Synced yesterday

READMEChangelog (9)Dependencies (4)Versions (14)Used By (3)

Concept DBAL
============

[](#concept-dbal)

[![Concept](https://camo.githubusercontent.com/e745f492a31d791af8a19eee36a1fa98382320b3e17d448c76596dbf5b41011d/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f436f6e636570742d65636f73797374656d2d76696f6c65742e737667)](https://github.com/Concept-Labs)[![License](https://camo.githubusercontent.com/a549a7a30bacba7bfceebdc207a8e86c3f2c02995a2527640dca30048fd2b64e/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c6963656e73652d417061636865253230322e302d626c75652e737667)](LICENSE)[![PHP Version](https://camo.githubusercontent.com/d840cef9807c8f76051ad687841d67f4d830c84e0d83236968e53124ef6742d5/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f7068702d253345253344382e322d3838393242462e737667)](https://php.net/)

A **low-level, foundational tool** for building database abstractions in PHP 8.2+. Part of the [Concept Ecosystem](https://github.com/Concept-Labs), designed specifically for **Dependency Injection** using [Singularity Container](https://github.com/Concept-Labs/singularity).

> **⚠️ Important:** DBAL is **NOT an ORM or ActiveRecord** - it's a low-level query builder that you use to **BUILD** ORMs, ActiveRecord, Repositories, Collections, and other data patterns. Think of it as **LEGO blocks** for your data layer.

What DBAL Is
------------

[](#what-dbal-is)

- ✅ **Low-level query builder** - Programmatic SQL construction
- ✅ **Foundation for abstractions** - Build ORMs, ActiveRecord, Repositories on top
- ✅ **Type-safe primitives** - Building blocks for your data layer
- ✅ **Expression-based** - Built on [concept-labs/expression](https://github.com/Concept-Labs/expression)

What DBAL Is Not
----------------

[](#what-dbal-is-not)

- ❌ **Not an ORM** - Doesn't map tables to objects (build your own!)
- ❌ **Not ActiveRecord** - No model classes (implement your own!)
- ❌ **Not a complete solution** - Provides primitives, not patterns (you choose the patterns!)

See **[Building on DBAL](docs/building-on-dbal.md)** for examples of building ActiveRecord, ORMs, Repositories, Collections, and more.

Features
--------

[](#features)

- 🎯 **Fluent Query Builder** - Intuitive, chainable API built on [concept-labs/expression](https://github.com/Concept-Labs/expression)
- 🔧 **Type-Safe** - Leverages PHP 8.2+ features for better type safety
- 🏗️ **Clean Architecture** - Interface-driven design with clear separation of concerns
- 💉 **DI-First** - Designed for dependency injection with Singularity container
- 🚀 **Performance** - Efficient query building with prototype pattern
- 🔌 **Extensible** - Easy to extend with custom builders and expressions
- 🌐 **Framework Agnostic** - Works standalone or integrates with modern frameworks
- 📦 **Ecosystem Integration** - Part of Concept-Labs packages working seamlessly together

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

[](#quick-start)

### Installation

[](#installation)

```
composer require concept-labs/dbal
```

### With Dependency Injection (Recommended)

[](#with-dependency-injection-recommended)

DBAL is designed from the ground up for dependency injection with [Singularity Container](https://github.com/Concept-Labs/singularity), leveraging the powerful [concept-labs/expression](https://github.com/Concept-Labs/expression) system for building complex SQL expressions.

#### Basic DI Usage

[](#basic-di-usage)

```
use Concept\DBAL\DbalManagerInterface;

// Inject DbalManager - the primary service of this package
class UserRepository {
    public function __construct(
        private DbalManagerInterface $dbal
    ) {}

    public function findActiveUsers(): array {
        // Access DML operations through dbal manager
        return $this->dbal->dml()
            ->select('id', 'name', 'email', 'created_at')
            ->from('users')
            ->where($this->dbal->dml()->expr()->condition('status', '=', 'active'))
            ->orderBy('created_at', 'DESC')
            ->limit(10)
            ->execute();
    }
}
```

#### Advanced Expression Building

[](#advanced-expression-building)

Build complex conditions with the expression system:

```
class UserRepository {
    public function __construct(private DbalManagerInterface $dbal) {}

    /**
     * Advanced filtering with grouped conditions
     */
    public function findUsers(array $filters): array {
        $expr = $this->dbal->dml()->expr();

        // Build complex conditions: (age >= 18 AND status = 'active') OR role = 'admin'
        $condition = $expr->group(
            $expr->group(
                $expr->condition('age', '>=', 18),
                'AND',
                $expr->condition('status', '=', 'active')
            ),
            'OR',
            $expr->condition('role', '=', 'admin')
        );

        return $this->dbal->dml()
            ->select('id', 'name', 'email', 'role', 'age')
            ->from('users')
            ->where($condition)
            ->orderBy('name')
            ->execute();
    }

    /**
     * Dynamic search with multiple criteria
     */
    public function searchUsers(?string $query = null, ?array $roles = null, ?int $minAge = null): array {
        $expr = $this->dbal->dml()->expr();
        $select = $this->dbal->dml()
            ->select('*')
            ->from('users');

        // Text search across multiple columns
        if ($query) {
            $pattern = "%{$query}%";
            $searchCondition = $expr->group(
                $expr->like('name', $pattern),
                'OR',
                $expr->group(
                    $expr->like('email', $pattern),
                    'OR',
                    $expr->like('bio', $pattern)
                )
            );
            $select->where($searchCondition);
        }

        // Filter by roles using IN clause
        if ($roles) {
            $select->where($expr->in('role', $roles));
        }

        // Age filter
        if ($minAge) {
            $select->where($expr->condition('age', '>=', $minAge));
        }

        return $select->execute();
    }
}
```

#### Expression Composition &amp; Reusability

[](#expression-composition--reusability)

Create reusable expression components for consistent logic:

```
use Concept\DBAL\DML\Expression\SqlExpressionInterface;

class UserExpressions {
    public function __construct(private DbalManagerInterface $dbal) {}

    /**
     * Reusable expression: active users
     */
    public function isActive(): SqlExpressionInterface {
        return $this->dbal->dml()->expr()->condition('status', '=', 'active');
    }

    /**
     * Reusable expression: adult users
     */
    public function isAdult(): SqlExpressionInterface {
        return $this->dbal->dml()->expr()->condition('age', '>=', 18);
    }

    /**
     * Reusable expression: verified email
     */
    public function isVerified(): SqlExpressionInterface {
        return $this->dbal->dml()->expr()->condition('email_verified', '=', true);
    }

    /**
     * Compose expressions: active adult users
     */
    public function isActiveAdult(): SqlExpressionInterface {
        $expr = $this->dbal->dml()->expr();
        return $expr->group($this->isActive(), 'AND', $this->isAdult());
    }

    /**
     * Soft delete scope
     */
    public function notDeleted(): SqlExpressionInterface {
        return $this->dbal->dml()->expr()->condition('deleted_at', 'IS', null);
    }
}

class UserRepository {
    public function __construct(
        private DbalManagerInterface $dbal,
        private UserExpressions $userExpr
    ) {}

    public function getActiveAdultUsers(): array {
        return $this->dbal->dml()
            ->select('*')
            ->from('users')
            ->where($this->userExpr->isActiveAdult())
            ->where($this->userExpr->notDeleted())
            ->execute();
    }
}
```

#### Aggregate Functions &amp; Analytics

[](#aggregate-functions--analytics)

Leverage SQL aggregate functions through expressions:

```
class AnalyticsRepository {
    public function __construct(private DbalManagerInterface $dbal) {}

    /**
     * User statistics with aggregates
     */
    public function getUserStats(): array {
        $expr = $this->dbal->dml()->expr();

        return $this->dbal->dml()
            ->select(
                'status',
                $expr->count('*', 'total_users'),
                $expr->avg('age', 'average_age'),
                $expr->min('created_at', 'first_signup'),
                $expr->max('created_at', 'last_signup')
            )
            ->from('users')
            ->where($expr->condition('deleted_at', 'IS', null))
            ->groupBy('status')
            ->execute();
    }

    /**
     * Revenue analysis with CASE expressions
     */
    public function getRevenueByTier(): array {
        $expr = $this->dbal->dml()->expr();

        // Categorize orders by value using CASE
        $tierCase = $expr->case(
            $expr->condition('total', '>=', 1000),
            'Premium',
            $expr->case(
                $expr->condition('total', '>=', 100),
                'Standard',
                'Basic'
            )
        );

        return $this->dbal->dml()
            ->select(
                $expr->alias('tier', $tierCase),
                $expr->count('*', 'order_count'),
                $expr->sum('total', 'total_revenue'),
                $expr->avg('total', 'avg_order_value')
            )
            ->from('orders')
            ->where($expr->condition('status', '=', 'completed'))
            ->groupBy('tier')
            ->orderBy('total_revenue', 'DESC')
            ->execute();
    }
}
```

#### Dynamic Filter Builder Pattern

[](#dynamic-filter-builder-pattern)

Build filters dynamically based on user input:

```
class FilterBuilder {
    private array $conditions = [];

    public function __construct(private DbalManagerInterface $dbal) {}

    /**
     * Add a simple condition
     */
    public function addCondition(string $column, string $operator, mixed $value): self {
        $this->conditions[] = $this->dbal->dml()->expr()->condition($column, $operator, $value);
        return $this;
    }

    /**
     * Add an IN condition
     */
    public function addIn(string $column, array $values): self {
        if (!empty($values)) {
            $this->conditions[] = $this->dbal->dml()->expr()->in($column, $values);
        }
        return $this;
    }

    /**
     * Add a LIKE condition
     */
    public function addLike(string $column, string $pattern): self {
        $this->conditions[] = $this->dbal->dml()->expr()->like($column, $pattern);
        return $this;
    }

    /**
     * Add a date range condition
     */
    public function addDateRange(string $column, ?string $from = null, ?string $to = null): self {
        $expr = $this->dbal->dml()->expr();

        if ($from) {
            $this->conditions[] = $expr->condition($column, '>=', $from);
        }
        if ($to) {
            $this->conditions[] = $expr->condition($column, '=', $params['min_price']);
        }
        if (isset($params['max_price'])) {
            $filter->addCondition('price', '', 18))
    ->orderBy('name')
    ->limit(10)
    ->execute();

// INSERT Query
$dbal->dml()->insert('users')
    ->values([
        'name' => 'John Doe',
        'email' => 'john@example.com',
        'created_at' => date('Y-m-d H:i:s')
    ])
    ->execute();

// UPDATE Query
$dbal->dml()->update('users')
    ->set('status', 'inactive')
    ->where($dbal->dml()->expr()->condition('last_login', '
