Query Builder

ZephyrPHP's query builder provides a fluent interface for building and executing database queries.

Basic Usage

Start a query from your model:

<?php

use App\Models\User;

$users = User::query()
    ->where('active', '=', true)
    ->all();

Selecting Data

Get All Records

// Get all users
$users = User::query()->all();

// Same as
$users = User::all();

Get First Record

$user = User::query()
    ->where('email', '=', 'john@example.com')
    ->first();

Find by ID

$user = User::find(1);

// Or via query
$user = User::query()
    ->where('id', '=', 1)
    ->first();

Where Clauses

Basic Where

$users = User::query()
    ->where('status', '=', 'active')
    ->all();

Multiple Conditions

// AND conditions (chained where)
$users = User::query()
    ->where('status', '=', 'active')
    ->where('role', '=', 'admin')
    ->all();

// All conditions must be true

Comparison Operators

// Equal
->where('status', '=', 'active')

// Not equal
->where('status', '!=', 'banned')

// Greater than
->where('age', '>', 18)

// Less than
->where('price', '<', 100)

// Greater than or equal
->where('quantity', '>=', 10)

// Less than or equal
->where('quantity', '<=', 100)

// LIKE
->where('name', 'LIKE', '%john%')

// IN
->where('status', 'IN', ['active', 'pending'])

// NOT IN
->where('role', 'NOT IN', ['banned', 'suspended'])

// IS NULL
->where('deleted_at', 'IS', null)

// IS NOT NULL
->where('email_verified_at', 'IS NOT', null)

Ordering

// Single order
$users = User::query()
    ->orderBy('name', 'ASC')
    ->all();

// Multiple orders
$users = User::query()
    ->orderBy('role', 'DESC')
    ->orderBy('name', 'ASC')
    ->all();

// Latest first (by created_at)
$users = User::query()
    ->orderBy('created_at', 'DESC')
    ->all();

Limiting Results

// Limit
$users = User::query()
    ->limit(10)
    ->all();

// Offset
$users = User::query()
    ->limit(10)
    ->offset(20)
    ->all();

// Get page 3 (10 per page)
$page = 3;
$perPage = 10;
$users = User::query()
    ->limit($perPage)
    ->offset(($page - 1) * $perPage)
    ->all();

Pagination

Built-in pagination support:

// 15 items per page
$result = User::query()
    ->where('active', '=', true)
    ->paginate(15);

// Access pagination data
$users = $result['items'];      // Array of users
$currentPage = $result['currentPage'];
$totalPages = $result['totalPages'];
$total = $result['total'];
$perPage = $result['perPage'];

Use in your controller:

public function index()
{
    $page = (int) request('page', 1);

    $result = User::query()
        ->where('active', '=', true)
        ->orderBy('name')
        ->paginate(15, $page);

    return $this->render('users/index', [
        'users' => $result['items'],
        'pagination' => $result
    ]);
}

Counting

// Count all records
$total = User::query()->count();

// Count with conditions
$activeCount = User::query()
    ->where('active', '=', true)
    ->count();

Aggregates

For aggregate functions, use the underlying Doctrine query builder:

use ZephyrPHP\Database\Database;

$db = Database::getInstance();
$qb = $db->getConnection()->createQueryBuilder();

// Sum
$total = $qb
    ->select('SUM(amount) as total')
    ->from('orders')
    ->where('status = ?')
    ->setParameter(0, 'completed')
    ->fetchOne();

// Average
$avg = $qb
    ->select('AVG(price) as average')
    ->from('products')
    ->fetchOne();

// Min/Max
$result = $qb
    ->select('MIN(price) as min_price, MAX(price) as max_price')
    ->from('products')
    ->fetchAssociative();

Combining Queries

// Complex query
$users = User::query()
    ->where('active', '=', true)
    ->where('role', '=', 'admin')
    ->where('created_at', '>', '2024-01-01')
    ->orderBy('name', 'ASC')
    ->limit(10)
    ->all();

Raw Doctrine Queries

For complex queries, use Doctrine's query builder directly:

use ZephyrPHP\Database\Database;

$db = Database::getInstance();
$qb = $db->getConnection()->createQueryBuilder();

$results = $qb
    ->select('u.*, COUNT(o.id) as order_count')
    ->from('users', 'u')
    ->leftJoin('u', 'orders', 'o', 'u.id = o.user_id')
    ->where('u.active = :active')
    ->groupBy('u.id')
    ->having('COUNT(o.id) > :min_orders')
    ->setParameter('active', true)
    ->setParameter('min_orders', 5)
    ->orderBy('order_count', 'DESC')
    ->fetchAllAssociative();

DQL Queries

Use Doctrine Query Language for object queries:

use ZephyrPHP\Database\Database;

$db = Database::getInstance();
$em = $db->getEntityManager();

$query = $em->createQuery(
    'SELECT u FROM App\Models\User u
     WHERE u.active = true
     ORDER BY u.createdAt DESC'
);

$users = $query->getResult();

// With parameters
$query = $em->createQuery(
    'SELECT u FROM App\Models\User u
     WHERE u.role = :role AND u.createdAt > :date'
);
$query->setParameter('role', 'admin');
$query->setParameter('date', new \DateTime('-30 days'));

$users = $query->getResult();
Performance Tip

Use limit() when you only need a subset of records. Fetching all records can be slow and memory-intensive for large tables.