PHPackages                             marwen-brini/bob-the-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. marwen-brini/bob-the-builder

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

marwen-brini/bob-the-builder
============================

A complete ORM and query builder for PHP with Laravel-like fluent syntax, models, relationships, and migrations

3.0.1(5mo ago)127MITPHPPHP ^8.1|^8.2|^8.3|^8.4CI passing

Since Sep 13Pushed 5mo agoCompare

[ Source](https://github.com/Marwen-Brini/bob-the-builder)[ Packagist](https://packagist.org/packages/marwen-brini/bob-the-builder)[ Docs](https://github.com/Marwen-Brini/bob-the-builder)[ GitHub Sponsors](https://github.com/Marwen-Brini)[ RSS](/packages/marwen-brini-bob-the-builder/feed)WikiDiscussions main Synced today

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

Bob Query Builder
=================

[](#bob-query-builder)

A highly optimized, standalone PHP query builder with Laravel-like fluent syntax. Originally designed to enhance Quantum ORM's query building capabilities, **Bob Query Builder is a fully independent package that can be used in ANY PHP project** - from WordPress plugins to modern PHP frameworks, microservices, or standalone applications.

[![PHP Version](https://camo.githubusercontent.com/cc9cdea9aa96b40a822425e981b0a030e3371202973c7d57b74e8e99834f81dc/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f7068702d253545382e312d626c7565)](https://www.php.net)[![License](https://camo.githubusercontent.com/f8df3091bbe1149f398a5369b2c39e896766f9f6efba3477c63e9b4aa940ef14/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d677265656e)](LICENSE)[![Tests](https://camo.githubusercontent.com/e60785278539084428554bee5994ce11b9e94c3d06e353c1590d79d0bd0f00d9/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f74657374732d3137373325323070617373696e672d627269676874677265656e)](https://github.com/Marwen-Brini/bob-the-builder/actions)[![Coverage](https://camo.githubusercontent.com/32855e94577df9d0a30995653b17d33a5fbfdf644518f96ea0374313397d19b7/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f636f7665726167652d3130302532352d627269676874677265656e)](https://github.com/Marwen-Brini/bob-the-builder)[![Documentation](https://camo.githubusercontent.com/600ee1b3d4e6941934e2ab1342395de9f11a96232a7b6f2683d2a85585246402/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f646f63732d7669746570726573732d707572706c65)](https://marwen-brini.github.io/bob-the-builder/)

Why Bob Query Builder?
----------------------

[](#why-bob-query-builder)

While initially created to modernize Quantum ORM's query building capabilities, Bob Query Builder was designed from the ground up as a **universal PHP query builder** that can enhance ANY PHP application:

- ✅ **Framework Agnostic** - Use it with Laravel, Symfony, WordPress, or vanilla PHP
- ✅ **Zero Lock-in** - No framework dependencies, just pure PHP and PDO
- ✅ **Modern PHP** - Built for PHP 8.1+ with full type safety
- ✅ **Production Ready** - 1773 tests, 100% passing, battle-tested
- ✅ **High Performance** - &lt;10ms query building overhead, handles 50k+ rows efficiently

Features
--------

[](#features)

- 🚀 **Full ORM with ActiveRecord** - Complete ORM layer with models and relationships (v2.0)
- 🔗 **Laravel-like Relationships** - HasOne, HasMany, BelongsTo, BelongsToMany with eager loading
- 🗄️ **Database Migrations** - Complete migration system with versioning and rollbacks (v3.0)
- 🏗️ **Schema Builder** - Fluent interface for creating and modifying database tables
- 🔍 **Schema Inspector** - Reverse engineer existing databases and generate migrations
- 🌐 **WordPress Schema Support** - Specialized helpers for WordPress/WooCommerce tables
- 💼 **Laravel-like Fluent Interface** - Familiar, expressive query builder syntax
- 🔧 **Database Agnostic** - Support for MySQL, PostgreSQL, SQLite via PDO
- 🎯 **Zero Dependencies** - Only requires PHP and PDO
- ⚡ **High Performance** - Query caching, prepared statements, 1M+ rows/second streaming
- 🧪 **Fully Tested** - 1773 tests with Pest, 100% code coverage
- 🔒 **Secure** - Automatic SQL injection prevention via parameter binding
- 📦 **Modular** - Easy integration with ANY PHP project, use as query builder or full ORM
- 🔄 **Transaction Support** - Including savepoints for nested transactions
- 📊 **PSR-3 Logging** - Built-in query logging with slow query detection
- 💾 **Memory Efficient** - Stream 50k+ rows with minimal memory usage
- 🎁 **Collections** - Powerful collection class for working with result sets
- 🎪 **Event System** - Hook into migration lifecycle with custom event listeners

Recent Updates (v3.0.0) 🎉
-------------------------

[](#recent-updates-v300-)

### 🗄️ Complete Migration System &amp; Schema Builder

[](#️-complete-migration-system--schema-builder)

Bob v3.0 introduces a comprehensive database migration and schema management system:

- **Schema Builder** - Fluent interface for creating and modifying database tables across MySQL, PostgreSQL, and SQLite
- **Migration System** - Complete migration lifecycle management with versioning, rollbacks, and batch tracking
- **WordPress Support** - Specialized `WordPressBlueprint` with helpers for WordPress and WooCommerce schemas
- **Schema Inspector** - Reverse engineer existing databases and generate migration files automatically
- **Event System** - Hook into migration lifecycle events for logging and custom workflows
- **Migration Features**:
    - Dependency resolution between migrations
    - Transaction support with automatic rollback on failure
    - Lifecycle hooks (`before()`, `after()`)
    - Pretend mode for safe testing
    - Batch tracking and status reporting

See the [Database Migrations &amp; Schema Builder](#database-migrations--schema-builder-v30) section for complete documentation.

Previous Updates (v2.2.2)
-------------------------

[](#previous-updates-v222)

### 🎯 100% Code Coverage Achieved!

[](#-100-code-coverage-achieved)

The test suite now has **complete 100% code coverage** across all components:

- ✅ **1773 tests passing** with 4387 assertions
- ✅ **Model class**: Full coverage including edge cases for existing ID updates
- ✅ **All test failures resolved**: Fixed naming conflicts and relationship configurations
- ✅ **Enhanced test reliability**: Better handling of complex scenarios

### 🛠️ Test Suite Improvements

[](#️-test-suite-improvements)

- Fixed class naming conflicts in Issue #13 debug tests
- Updated Issue #15 test expectations to reflect corrected behavior
- Improved BelongsToMany relationship tests for WordPress-style tables
- Added comprehensive tests for models with existing database IDs

Previous Updates (v2.2.1)
-------------------------

[](#previous-updates-v221)

### 🛠️ Bug Fixes

[](#️-bug-fixes)

#### Global Scope Field References in WHERE Clauses

[](#global-scope-field-references-in-where-clauses)

Fixed an important issue with global scopes and field references:

- ✅ **Global scopes now apply in toSql()** - SQL generation now includes global scope modifications
- ✅ **Prevents duplicate scope application** - Added tracking to ensure scopes apply only once
- ✅ **No side effects** - Clone builder in toSql() to avoid modifying original instance

Previous Updates (v2.1.1)
-------------------------

[](#previous-updates-v211)

### 🛠️ Critical Bug Fixes

[](#️-critical-bug-fixes)

#### Table Prefix Handling in JOIN Clauses

[](#table-prefix-handling-in-join-clauses)

Fixed all table prefix issues reported in production environments:

- ✅ **Double prefix bug fixed** - No more duplicate prefixes in JOIN WHERE clauses
- ✅ **Global scopes with JOINs** - Global scopes containing JOINs now work correctly
- ✅ **Table aliases** - Proper handling of aliases in SELECT statements with JOINs
- ✅ **Subqueries** - `whereIn()` with subquery builders handles prefixes correctly

#### New Model Method: forceFill()

[](#new-model-method-forcefill)

Added Laravel-compatible `forceFill()` method for bypassing mass assignment:

```
// Hydrate models from database without checking fillable/guarded
$model->forceFill($databaseRow); // Bypasses mass assignment protection
```

Previous Updates (v2.1.0)
-------------------------

[](#previous-updates-v210)

### 🚀 New Features

[](#-new-features)

#### Query Caching for exists()

[](#query-caching-for-exists)

Optimize repeated existence checks with the new opt-in caching mechanism:

```
$builder = $connection->table('users')
    ->enableExistsCache(120) // Cache for 2 minutes
    ->where('email', 'user@example.com');

// First call - hits database
$exists = $builder->exists();

// Subsequent calls within 2 minutes - uses cache
$exists = $builder->exists(); // No database query!
```

#### Global Scopes in Relationships

[](#global-scopes-in-relationships)

Relationships now properly inherit global scopes:

```
// Global scopes automatically apply to relationships
$user->posts()->get(); // Includes global scopes from Post model

// Or disable for specific queries
$user->posts()->withoutGlobalScopes()->get();
```

### Previous Updates (v2.0.7)

[](#previous-updates-v207)

- **Global Scopes Support** - Laravel-style instance-level global scopes
- **Nested WHERE Closures** - Fixed SQL generation for nested conditions
- **Delete Bindings Isolation** - Fixed parameter binding in delete operations
- **Timestamp Handling** - Properly respects `$timestamps = false`
- **Scope Chaining** - Full support for chaining custom scope methods
- **Aggregate Functions** - Automatic detection and handling
- **Subquery Support** - Fixed whereIn() with Builder subqueries

#### 🔒 PHP 8.4+ Compatibility

[](#-php-84-compatibility)

- Full compatibility with PHP 8.1, 8.2, 8.3, and 8.4
- All implicit nullable parameter warnings fixed

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

[](#requirements)

- PHP 8.1, 8.2, 8.3, or 8.4
- PDO extension
- Database-specific PDO driver (pdo\_mysql, pdo\_pgsql, pdo\_sqlite)

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

[](#installation)

Install via Composer:

```
composer require marwen-brini/bob-the-builder
```

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

[](#quick-start)

```
use Bob\Database\Connection;

// Configure your database connection
$connection = new Connection([
    'driver' => 'mysql',
    'host' => '127.0.0.1',
    'port' => 3306,
    'database' => 'your_database',
    'username' => 'your_username',
    'password' => 'your_password',
    'charset' => 'utf8mb4',
    'collation' => 'utf8mb4_unicode_ci',
    'prefix' => '',
]);

// Start building queries
$users = $connection->table('users')
    ->where('active', true)
    ->where('age', '>=', 18)
    ->orderBy('name')
    ->limit(10)
    ->get();
```

Configuration
-------------

[](#configuration)

### Fetch Mode

[](#fetch-mode)

By default, Bob Query Builder returns query results as associative arrays. You can configure this behavior:

```
// Option 1: Configure via connection config
$connection = new Connection([
    'driver' => 'mysql',
    'database' => 'mydb',
    // ... other config
    'fetch' => PDO::FETCH_OBJ,  // Return objects instead of arrays
]);

// Option 2: Change dynamically at runtime
$connection->setFetchMode(PDO::FETCH_OBJ);  // Use objects
$users = $connection->table('users')->get(); // Returns array of stdClass objects

$connection->setFetchMode(PDO::FETCH_ASSOC); // Back to arrays (default)
$users = $connection->table('users')->get(); // Returns array of associative arrays
```

Available fetch modes:

- `PDO::FETCH_ASSOC` - Associative arrays (default)
- `PDO::FETCH_OBJ` - stdClass objects
- `PDO::FETCH_NUM` - Numeric arrays
- `PDO::FETCH_BOTH` - Both numeric and associative arrays
- Any other PDO fetch mode constant

Basic Usage
-----------

[](#basic-usage)

### Select Queries

[](#select-queries)

```
// Get all records
$users = $connection->table('users')->get();

// Get specific columns
$users = $connection->table('users')
    ->select('id', 'name', 'email')
    ->get();

// Get first record
$user = $connection->table('users')
    ->where('email', 'john@example.com')
    ->first();

// Get single value
$email = $connection->table('users')
    ->where('id', 1)
    ->value('email');
```

### Where Clauses

[](#where-clauses)

```
// Basic where
$users = $connection->table('users')
    ->where('status', 'active')
    ->get();

// Multiple conditions
$users = $connection->table('users')
    ->where('status', 'active')
    ->where('age', '>', 18)
    ->get();

// Or where
$users = $connection->table('users')
    ->where('role', 'admin')
    ->orWhere('role', 'moderator')
    ->get();

// Where in
$users = $connection->table('users')
    ->whereIn('id', [1, 2, 3])
    ->get();

// Where between
$users = $connection->table('users')
    ->whereBetween('age', [18, 65])
    ->get();

// Where null
$users = $connection->table('users')
    ->whereNull('deleted_at')
    ->get();
```

### Joins

[](#joins)

```
// Inner join
$users = $connection->table('users')
    ->join('posts', 'users.id', '=', 'posts.user_id')
    ->select('users.*', 'posts.title')
    ->get();

// Left join
$users = $connection->table('users')
    ->leftJoin('posts', 'users.id', '=', 'posts.user_id')
    ->get();

// Multiple joins
$users = $connection->table('users')
    ->join('posts', 'users.id', '=', 'posts.user_id')
    ->join('comments', 'posts.id', '=', 'comments.post_id')
    ->get();
```

### Aggregates

[](#aggregates)

```
// Count
$count = $connection->table('users')->count();

// Sum
$total = $connection->table('orders')->sum('amount');

// Average
$avg = $connection->table('products')->avg('price');

// Min/Max
$min = $connection->table('products')->min('price');
$max = $connection->table('products')->max('price');
```

### Insert

[](#insert)

```
// Single record
$connection->table('users')->insert([
    'name' => 'John Doe',
    'email' => 'john@example.com',
    'password' => bcrypt('password')
]);

// Multiple records
$connection->table('users')->insert([
    ['name' => 'John', 'email' => 'john@example.com'],
    ['name' => 'Jane', 'email' => 'jane@example.com']
]);

// Insert and get ID
$id = $connection->table('users')->insertGetId([
    'name' => 'John Doe',
    'email' => 'john@example.com'
]);
```

### Update

[](#update)

```
// Update records
$affected = $connection->table('users')
    ->where('id', 1)
    ->update(['status' => 'active']);

// Update with increment
$connection->table('posts')
    ->where('id', 1)
    ->update(['views' => $connection->raw('views + 1')]);
```

### Delete

[](#delete)

```
// Delete records
$deleted = $connection->table('users')
    ->where('status', 'inactive')
    ->delete();

// Delete by ID
$connection->table('users')->delete(5);

// Truncate table
$connection->table('users')->truncate();
```

### Transactions

[](#transactions)

```
// Basic transaction
$connection->transaction(function ($connection) {
    $connection->table('users')->insert([...]);
    $connection->table('posts')->insert([...]);
});

// Manual transaction control
$connection->beginTransaction();
try {
    // Your queries here
    $connection->commit();
} catch (Exception $e) {
    $connection->rollBack();
    throw $e;
}

// Transaction with retries
$connection->transaction(function ($connection) {
    // Your queries here
}, attempts: 3);
```

### Raw Expressions

[](#raw-expressions)

```
// Raw select
$users = $connection->table('users')
    ->select($connection->raw('COUNT(*) as user_count'))
    ->get();

// Raw where
$users = $connection->table('users')
    ->where('created_at', '>', $connection->raw('NOW() - INTERVAL 1 DAY'))
    ->get();
```

### Pagination

[](#pagination)

```
// Simple pagination
$page = 2;
$perPage = 15;

$users = $connection->table('users')
    ->page($page, $perPage)
    ->get();

// Manual limit/offset
$users = $connection->table('users')
    ->limit(10)
    ->offset(20)
    ->get();
```

### Chunking

[](#chunking)

Process large datasets efficiently:

```
$connection->table('users')->chunk(100, function ($users) {
    foreach ($users as $user) {
        // Process user
    }
});
```

### Cursor Streaming

[](#cursor-streaming)

For extremely large datasets (50k+ rows), use cursor for memory-efficient processing:

```
// Stream millions of rows with minimal memory usage
foreach ($connection->table('users')->cursor() as $user) {
    // Process one user at a time
    // Memory usage stays constant regardless of dataset size
    processUser($user);
}

// Performance: 1M+ rows/second throughput
// Memory: ~8MB for 15,000 rows
```

### Query Debugging

[](#query-debugging)

```
// Enable query logging
$connection->enableQueryLog();

// Run queries
$users = $connection->table('users')->get();

// Get query log
$queries = $connection->getQueryLog();
print_r($queries);

// Get SQL without executing
$sql = $connection->table('users')
    ->where('active', true)
    ->toSql();
echo $sql; // select * from "users" where "active" = ?

// Get bindings
$bindings = $connection->table('users')
    ->where('active', true)
    ->getBindings();
print_r($bindings); // [true]
```

Database Configuration
----------------------

[](#database-configuration)

### MySQL/MariaDB

[](#mysqlmariadb)

```
$connection = new Connection([
    'driver' => 'mysql',
    'host' => '127.0.0.1',
    'port' => 3306,
    'database' => 'database_name',
    'username' => 'username',
    'password' => 'password',
    'charset' => 'utf8mb4',
    'collation' => 'utf8mb4_unicode_ci',
    'prefix' => '',
    'options' => [
        PDO::ATTR_PERSISTENT => false,
    ]
]);
```

### PostgreSQL

[](#postgresql)

```
$connection = new Connection([
    'driver' => 'pgsql',
    'host' => '127.0.0.1',
    'port' => 5432,
    'database' => 'database_name',
    'username' => 'username',
    'password' => 'password',
    'prefix' => '',
    'schema' => 'public',
]);
```

### SQLite

[](#sqlite)

```
$connection = new Connection([
    'driver' => 'sqlite',
    'database' => '/path/to/database.sqlite',
    'prefix' => '',
]);

// In-memory database (great for testing)
$connection = new Connection([
    'driver' => 'sqlite',
    'database' => ':memory:',
    'prefix' => '',
]);
```

ORM &amp; Model Features
------------------------

[](#orm--model-features)

### Model Definition

[](#model-definition)

Bob v2.0 introduces a full ORM layer with Laravel-inspired models:

```
use Bob\Database\Model;

class User extends Model
{
    protected $table = 'users';
    protected $primaryKey = 'id';
    protected $fillable = ['name', 'email', 'password'];

    // Define relationships
    public function posts()
    {
        return $this->hasMany(Post::class);
    }

    public function profile()
    {
        return $this->hasOne(Profile::class);
    }

    public function roles()
    {
        return $this->belongsToMany(Role::class, 'user_roles');
    }
}
```

### Relationships

[](#relationships)

#### One-to-One (HasOne)

[](#one-to-one-hasone)

```
class User extends Model
{
    public function profile()
    {
        return $this->hasOne(Profile::class);
    }
}

// Usage
$user = User::find(1);
$profile = $user->profile; // Automatically loads the profile
```

#### One-to-Many (HasMany)

[](#one-to-many-hasmany)

```
class User extends Model
{
    public function posts()
    {
        return $this->hasMany(Post::class);
    }
}

// Usage
$user = User::find(1);
$posts = $user->posts; // Returns a Collection of Post models
```

#### Many-to-One (BelongsTo)

[](#many-to-one-belongsto)

```
class Post extends Model
{
    public function author()
    {
        return $this->belongsTo(User::class, 'user_id');
    }
}

// Usage
$post = Post::find(1);
$author = $post->author; // Loads the User model
```

#### Many-to-Many (BelongsToMany)

[](#many-to-many-belongstomany)

```
class User extends Model
{
    public function roles()
    {
        return $this->belongsToMany(Role::class, 'user_roles', 'user_id', 'role_id');
    }
}

// Usage
$user = User::find(1);
$roles = $user->roles; // Returns Collection of Role models

// Attach/Detach relationships
$user->roles()->attach($roleId);
$user->roles()->detach($roleId);
$user->roles()->sync([1, 2, 3]); // Sync to exact set of IDs
```

### Eager Loading

[](#eager-loading)

Prevent N+1 queries with eager loading:

```
// Load users with their posts and comments
$users = User::with('posts.comments')->get();

// Multiple relationships
$users = User::with(['posts', 'profile', 'roles'])->get();

// Eager loading with constraints
$users = User::with(['posts' => function($query) {
    $query->where('published', true);
}])->get();
```

### Model Queries

[](#model-queries)

Models provide an intuitive ActiveRecord interface:

```
// Find by primary key
$user = User::find(1);

// Find or fail (throws exception)
$user = User::findOrFail(1);

// Create new record
$user = User::create([
    'name' => 'John Doe',
    'email' => 'john@example.com'
]);

// Update existing
$user->update(['name' => 'Jane Doe']);

// Delete
$user->delete();

// Query builder integration
$users = User::where('active', true)
    ->orderBy('created_at', 'desc')
    ->limit(10)
    ->get();

// Aggregates
$count = User::where('role', 'admin')->count();
$avg = Product::avg('price');
```

### Collections

[](#collections)

Model queries return powerful Collection objects:

```
$users = User::all();

// Collection methods
$admins = $users->filter(fn($user) => $user->role === 'admin');
$names = $users->pluck('name');
$grouped = $users->groupBy('role');
$sorted = $users->sortBy('created_at');

// Map over items
$emails = $users->map(fn($user) => $user->email);

// Check if collection contains item
$hasAdmin = $users->contains('role', 'admin');
```

Database Migrations &amp; Schema Builder (v3.0)
-----------------------------------------------

[](#database-migrations--schema-builder-v30)

### Schema Builder

[](#schema-builder)

Create and modify database tables with an expressive, fluent interface:

```
use Bob\Schema\Schema;

// Create a new table
Schema::create('users', function (Blueprint $table) {
    $table->id();
    $table->string('name');
    $table->string('email')->unique();
    $table->timestamp('email_verified_at')->nullable();
    $table->string('password');
    $table->rememberToken();
    $table->timestamps();
});

// Modify existing table
Schema::table('users', function (Blueprint $table) {
    $table->string('phone')->nullable()->after('email');
    $table->index('phone');
});

// Drop table
Schema::dropIfExists('users');
```

### WordPress Schema Support

[](#wordpress-schema-support)

Bob includes specialized helpers for WordPress and WooCommerce table creation:

```
use Bob\Schema\Schema;

// Create WordPress-style post table
Schema::createWordPress('custom_posts', function (WordPressBlueprint $table) {
    $table->wpPost();           // All standard WordPress post columns
    $table->wpPostIndexes();    // Standard WordPress indexes
});

// Create custom meta table
Schema::createWordPress('custom_meta', function (WordPressBlueprint $table) {
    $table->wpMeta('custom');   // Creates: meta_id, custom_id, meta_key, meta_value
});

// Create WooCommerce order table
Schema::createWordPress('wc_custom_orders', function (WordPressBlueprint $table) {
    $table->wcOrder();          // All WooCommerce HPOS order columns
});
```

### Migration System

[](#migration-system)

Manage database schema changes with version-controlled migrations:

```
use Bob\Database\Migrations\Migration;
use Bob\Schema\Blueprint;
use Bob\Schema\Schema;

class CreateUsersTable extends Migration
{
    /**
     * Run the migrations.
     */
    public function up(): void
    {
        Schema::create('users', function (Blueprint $table) {
            $table->id();
            $table->string('name');
            $table->string('email')->unique();
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     */
    public function down(): void
    {
        Schema::dropIfExists('users');
    }
}
```

### Running Migrations

[](#running-migrations)

```
use Bob\Database\Migrations\MigrationRunner;
use Bob\Database\Migrations\MigrationRepository;
use Bob\Database\Connection;

$connection = new Connection([/* config */]);
$repository = new MigrationRepository($connection, 'migrations');
$runner = new MigrationRunner($connection, $repository, ['/path/to/migrations']);

// Run pending migrations
$runner->run();

// Rollback last batch
$runner->rollback();

// Rollback all migrations
$runner->reset();

// Drop all tables and re-run migrations
$runner->fresh();

// Rollback and re-run all migrations
$runner->refresh();

// Check migration status
$status = $runner->status();
```

### Migration Features

[](#migration-features)

- **Dependency Resolution** - Migrations can declare dependencies on other migrations
- **Transaction Support** - Run migrations within database transactions
- **Batch Tracking** - Track which migrations ran together
- **Lifecycle Hooks** - `before()` and `after()` methods for setup/cleanup
- **Event System** - Hook into migration events for logging and monitoring
- **Pretend Mode** - See what migrations would do without running them
- **Version Control** - Each migration is tracked with execution time and batch number

### Schema Inspector

[](#schema-inspector)

Reverse engineer existing databases and generate migration files:

```
use Bob\Schema\Inspector;

$inspector = new Inspector($connection);

// Get all tables
$tables = $inspector->getTables();

// Get table structure
$columns = $inspector->getColumns('users');
$indexes = $inspector->getIndexes('users');
$foreignKeys = $inspector->getForeignKeys('users');

// Generate migration from existing table
$migration = $inspector->generateMigration('users');
file_put_contents('2024_01_01_000000_create_users_table.php', $migration);
```

### Column Types

[](#column-types)

Bob supports all standard database column types:

```
// Numeric types
$table->id();                      // Auto-incrementing BIGINT
$table->bigInteger('votes');
$table->integer('count');
$table->smallInteger('votes');
$table->tinyInteger('active');
$table->decimal('amount', 8, 2);
$table->float('amount');
$table->double('amount');

// String types
$table->string('name', 100);
$table->text('description');
$table->longText('content');
$table->char('code', 4);

// Date/Time types
$table->date('birthday');
$table->dateTime('created_at');
$table->timestamp('updated_at');
$table->time('sunrise');
$table->timestamps();              // created_at + updated_at

// Other types
$table->boolean('active');
$table->json('metadata');
$table->binary('data');
$table->uuid('identifier');
$table->enum('status', ['active', 'inactive']);

// Column modifiers
$table->string('email')->nullable();
$table->string('name')->default('Guest');
$table->string('slug')->unique();
$table->integer('position')->unsigned();
$table->text('bio')->comment('User biography');
```

### Indexes and Constraints

[](#indexes-and-constraints)

```
// Indexes
$table->primary('id');
$table->unique('email');
$table->index('status');
$table->index(['user_id', 'created_at']);

// Foreign keys
$table->foreign('user_id')
    ->references('id')
    ->on('users')
    ->onDelete('cascade')
    ->onUpdate('cascade');

// Drop constraints
$table->dropPrimary('users_id_primary');
$table->dropUnique('users_email_unique');
$table->dropIndex('users_status_index');
$table->dropForeign('posts_user_id_foreign');
```

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

[](#advanced-features)

### Query Builder Cloning

[](#query-builder-cloning)

```
$baseQuery = $connection->table('users')->where('active', true);

// Clone for variations
$admins = $baseQuery->clone()->where('role', 'admin')->get();
$users = $baseQuery->clone()->where('role', 'user')->get();
```

### Subqueries

[](#subqueries)

```
$subquery = $connection->table('posts')
    ->select('user_id')
    ->where('published', true);

$users = $connection->table('users')
    ->whereIn('id', $subquery)
    ->get();
```

### Custom Grammars

[](#custom-grammars)

Extend the grammar for custom SQL dialects:

```
use Bob\Query\Grammar;

class CustomGrammar extends Grammar
{
    // Override methods for custom SQL generation
}

$connection->setQueryGrammar(new CustomGrammar());
```

Testing
-------

[](#testing)

Run the test suite:

```
# Run all tests
composer test

# Run with coverage
composer test:coverage

# Run specific test suite
vendor/bin/pest tests/Integration

# Run with verbose output
vendor/bin/pest -vvv
```

Performance Benchmarks
----------------------

[](#performance-benchmarks)

Bob Query Builder is highly optimized for real-world applications:

### Query Building Performance

[](#query-building-performance)

- **Simple SELECT**: ~0.02ms average overhead
- **Complex queries with joins**: ~0.1ms average overhead
- **Subqueries**: ~0.07ms average overhead
- **All query types**: &lt;10ms overhead guaranteed

### Large Dataset Handling

[](#large-dataset-handling)

- **Streaming**: 1M+ rows per second throughput
- **Memory usage**: ~8MB for 15,000 rows with cursor
- **50,000 rows**: Handled efficiently with &lt;30MB memory
- **Chunk processing**: Process millions of rows without memory issues

### Optimization Features

[](#optimization-features)

The query builder includes several optimization features:

- **Prepared Statement Caching**: Reuses prepared statements for identical queries
- **Connection Pooling**: Efficient connection management
- **Query Result Caching**: Optional caching of query results
- **Lazy Loading**: Use `cursor()` for memory-efficient iteration
- **Bulk Operations**: Optimized bulk inserts and updates
- **Statement Caching**: Second run of cached statements is significantly faster

Use Cases
---------

[](#use-cases)

Bob Query Builder is perfect for:

- **WordPress Plugins** - Modern query building without the overhead
- **Legacy PHP Applications** - Modernize database interactions incrementally
- **Microservices** - Lightweight, efficient database layer
- **API Development** - Clean, readable query construction
- **Any PHP Project** - From simple scripts to complex applications

Integration Examples
--------------------

[](#integration-examples)

### WordPress / Quantum ORM

[](#wordpress--quantum-orm)

```
use Bob\Database\Connection;

$connection = new Connection([
    'driver' => 'mysql',
    'host' => DB_HOST,
    'database' => DB_NAME,
    'username' => DB_USER,
    'password' => DB_PASSWORD,
    'prefix' => $wpdb->prefix,
]);

// Now use modern query building in WordPress!
$posts = $connection->table('posts')
    ->where('post_status', 'publish')
    ->orderBy('post_date', 'desc')
    ->limit(10)
    ->get();
```

### Standalone PHP Application

[](#standalone-php-application)

```
use Bob\Database\Connection;

$connection = new Connection([
    'driver' => 'sqlite',
    'database' => 'database.sqlite',
]);

$users = $connection->table('users')
    ->where('active', true)
    ->get();
```

### Integration with Any Framework

[](#integration-with-any-framework)

Bob Query Builder can be registered as a service in any dependency injection container:

```
// In your service provider or bootstrap
$container->singleton(Connection::class, function () {
    return new Connection(config('database'));
});
```

📚 Documentation
---------------

[](#-documentation)

Full documentation is available at ****

The documentation includes:

- Getting Started Guide
- Complete API Reference
- Database-specific Features
- Performance Optimization Tips
- WordPress Integration Guide
- CLI Tool Usage
- Migration from Other Query Builders
- Troubleshooting Guide

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

[](#contributing)

We welcome contributions! Please see [CONTRIBUTING.md](CONTRIBUTING.md) for details.

Testing Requirements
--------------------

[](#testing-requirements)

- Tests must be written before implementation (TDD)
- All tests must pass before merging
- Maintain 100% code coverage
- Follow PSR-12 coding standards

License
-------

[](#license)

The Bob Query Builder is open-sourced software licensed under the [MIT license](LICENSE).

Project Repository
------------------

[](#project-repository)

🔗 **GitHub**:

Credits
-------

[](#credits)

- Originally built to enhance Quantum ORM, but designed as a **standalone solution for ANY PHP project**
- Inspired by Laravel's Eloquent Query Builder
- Designed with modern PHP best practices and 100% test coverage
- Built with love for the PHP community

Support
-------

[](#support)

For bugs and feature requests, please use the [GitHub issues](https://github.com/Marwen-Brini/bob-the-builder/issues).

Roadmap
-------

[](#roadmap)

### Completed ✅

[](#completed-)

- Core query building functionality
- Multi-database support (MySQL, PostgreSQL, SQLite)
- Transaction support
- Prepared statement caching
- Query result caching
- Connection pooling
- Performance profiling
- PSR-3 logging integration
- Slow query detection
- Memory-efficient streaming (cursor/chunk)
- CLI tools for testing and query building
- Comprehensive test suite (1644 tests)
- Performance benchmarks

### v3.0 - Completed ✅

[](#v30---completed-)

- Schema builder with fluent interface
- Migration system with dependency resolution
- WordPress/WooCommerce schema helpers
- Schema inspector for reverse engineering
- Migration event system
- Transaction support for migrations

### Planned Features

[](#planned-features)

- Database seeding system
- Query builder macros/extensions
- Additional database support (SQL Server, Oracle)
- Query builder IDE helpers
- Advanced migration features (squashing, etc.)

###  Health Score

41

—

FairBetter than 87% of packages

Maintenance72

Regular maintenance activity

Popularity9

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity65

Established project with proven stability

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

Recently: every ~30 days

Total

10

Last Release

159d ago

Major Versions

v1.0.0 → 2.0.02025-09-22

2.2.2 → 3.0.02025-10-01

### Community

Maintainers

![](https://www.gravatar.com/avatar/c081aa8f05c4eec0f617cd95ebe284deea7279f694c18b084f3edfa2af992176?d=identicon)[Marwen-Brini](/maintainers/Marwen-Brini)

---

Top Contributors

[![Marwen-Brini](https://avatars.githubusercontent.com/u/23398443?v=4)](https://github.com/Marwen-Brini "Marwen-Brini (128 commits)")

---

Tags

laravelschemadatabaseormmysqlsqlitepostgresqlsqlpdomodeleloquentmigrationsquery builderactiverecordRelationships

###  Code Quality

TestsPest

Code StyleLaravel Pint

### Embed Badge

![Health badge](/badges/marwen-brini-bob-the-builder/health.svg)

```
[![Health](https://phpackages.com/badges/marwen-brini-bob-the-builder/health.svg)](https://phpackages.com/packages/marwen-brini-bob-the-builder)
```

###  Alternatives

[doctrine/dbal

Powerful PHP database abstraction layer (DBAL) with many features for database schema introspection and management.

9.7k605.0M6.8k](/packages/doctrine-dbal)[tommyknocker/pdo-database-class

Framework-agnostic PHP database library with unified API for MySQL, MariaDB, PostgreSQL, SQLite, MSSQL, and Oracle. Query Builder, caching, sharding, window functions, CTEs, JSON, migrations, ActiveRecord, CLI tools, AI-powered analysis. Zero external dependencies.

846.1k](/packages/tommyknocker-pdo-database-class)[cycle/database

DBAL, schema introspection, migration and pagination

71777.8k53](/packages/cycle-database)[aura/sqlschema

Provides facilities to read table names and table columns from a database using PDO.

44243.2k4](/packages/aura-sqlschema)[ramadan/easy-model

A Laravel package for enjoyably managing database queries.

111.6k](/packages/ramadan-easy-model)

PHPackages © 2026

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