craftix / lite-eloquent
Lightweight, dependency-free Eloquent-style PDO Query Builder for PHP
Installs: 1
Dependents: 0
Suggesters: 0
Security: 0
Stars: 0
Watchers: 0
Forks: 0
Open Issues: 0
pkg:composer/craftix/lite-eloquent
Requires
- php: >=8.2
- ext-pdo: *
Requires (Dev)
- phpunit/phpunit: ^10.0
This package is auto-updated.
Last update: 2025-12-02 00:47:27 UTC
README
Lite Eloquent is a lightweight, high-performance PHP database query builder and ORM-inspired library.
It provides an easy-to-use, fluent API for building SQL queries with support for joins,
where clauses, pagination, and bindingsβwithout the heavy dependencies.
β¨ Features
- π High-performance PHP database query builder
- π¦ Lightweight and dependency-free (only requires PDO)
- π Fluent, chainable API similar to Eloquent
- π Secure with proper parameter bindings (SQL injection protection)
- ποΈ Multi-dialect support (MySQL, Pgsql)
- π Pagination support (simple and length-aware)
- π Transaction support
- π Collection class with array-like operations
- π― Type-safe with PHP 8.2+ features
Supported Operations
- β
SELECTqueries with columns, joins, where clauses, ordering, limit - β
INSERTqueries (single and bulk) - β
UPDATEqueries with where clauses - β
DELETEqueries with where clauses - β
UPSERToperations (MySQL: ON DUPLICATE KEY UPDATE, Pgsql: ON CONFLICT) - β
INSERT OR IGNOREoperations - β
Complex
WHEREconditions (nested groups, IN, BETWEEN, NULL checks, LIKE, etc.) - β
JOINclauses (INNER, LEFT, RIGHT, FULL) - β Raw SQL expressions
- β Pagination (with total count or simple)
- β Database transactions
π¦ Installation
Install via Composer:
composer require craftix/lite-eloquent
Requirements:
- PHP >= 8.2
- PDO extension
π Quick Start
Basic Setup
<?php use Craftix\Eloquent\DB; use PDO; // Create a PDO connection $pdo = new PDO( 'mysql:host=localhost;dbname=db_name', 'username', 'password', [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION] ); // Initialize DB instance $db = new DB($pdo); // Start querying! $users = $db->table('users')->get();
Using Singleton Pattern
<?php use Craftix\Eloquent\DatabaseManager; use PDO; // Initialize singleton DatabaseManager::init( new PDO('mysql:host=localhost;dbname=db_name', 'username', 'password') ); // Use static methods $users = DatabaseManager::table('users')->get();
π Usage Examples
SELECT Queries
Basic Select
// Get all users $users = $db->table('users')->get(); // Select specific columns $users = $db->table('users') ->select('id', 'name', 'email') ->get(); // Get first record $user = $db->table('users')->first(); // Get single column as array $emails = $db->table('users')->pluck('email');
WHERE Clauses
// Simple where $users = $db->table('users') ->where('status', '=', 'active') ->get(); // Where with default operator (=) $users = $db->table('users') ->where('age', 25) ->get(); // Multiple conditions (AND) $users = $db->table('users') ->where('status', 'active') ->where('age', '>', 18) ->get(); // OR conditions $users = $db->table('users') ->where('status', 'active') ->orWhere('status', 'pending') ->get(); // WHERE IN $users = $db->table('users') ->whereIn('id', [1, 2, 3, 4, 5]) ->get(); // WHERE NOT IN $users = $db->table('users') ->whereNotIn('status', ['banned', 'deleted']) ->get(); // WHERE BETWEEN $users = $db->table('users') ->whereBetween('age', 18, 65) ->get(); // WHERE NULL / NOT NULL $users = $db->table('users') ->whereNull('deleted_at') ->get(); $users = $db->table('users') ->whereNotNull('email_verified_at') ->get(); // WHERE LIKE $users = $db->table('users') ->whereLike('name', '%john%') ->get(); // WHERE NOT LIKE $users = $db->table('users') ->whereNotLike('email', '%@spam.com') ->get(); // Nested WHERE groups $users = $db->table('users') ->where('status', 'active') ->where(function($query) { $query->where('age', '>', 18) ->orWhere('verified', true); }) ->get();
JOIN Clauses
// INNER JOIN $users = $db->table('users') ->join('profiles', 'users.id', '=', 'profiles.user_id') ->select('users.*', 'profiles.bio') ->get(); // LEFT JOIN $users = $db->table('users') ->leftJoin('profiles', 'users.id', '=', 'profiles.user_id') ->get(); // RIGHT JOIN $users = $db->table('users') ->rightJoin('profiles', 'users.id', '=', 'profiles.user_id') ->get(); // Complex JOIN with conditions $users = $db->table('users') ->join('orders', function($join) { $join->on('users.id', '=', 'orders.user_id') ->where('orders.status', '=', 'completed'); }) ->get(); // Multiple JOINs $orders = $db->table('orders') ->join('users', 'orders.user_id', '=', 'users.id') ->join('products', 'orders.product_id', '=', 'products.id') ->select('orders.*', 'users.name', 'products.title') ->get();
Ordering and Limits
// ORDER BY $users = $db->table('users') ->orderBy('created_at', 'DESC') ->get(); // Multiple ORDER BY $users = $db->table('users') ->orderBy('status', 'ASC') ->orderBy('name', 'ASC') ->get(); // ORDER BY DESC (shortcut) $users = $db->table('users') ->orderByDesc('created_at') ->get(); // Random order $users = $db->table('users') ->inRandomOrder() ->get(); // LIMIT $users = $db->table('users') ->limit(10) ->get(); // OFFSET $users = $db->table('users') ->offset(20) ->limit(10) ->get(); // DISTINCT $emails = $db->table('users') ->distinct() ->select('email') ->get();
Pagination
// Length-aware pagination (with total count) $paginator = $db->table('users') ->paginate($page = 1, $perPage = 15); // Access pagination data $users = $paginator->items(); // Array of users $total = $paginator->total(); // Total count $currentPage = $paginator->currentPage(); $perPage = $paginator->perPage(); $totalPages = $paginator->totalPages(); $hasMore = $paginator->hasMorePages(); // Pagination info $info = $paginator->getPaginationInfo(); // Returns: ['total', 'perPage', 'from', 'to', 'pages', 'currentPage', 'previousPage', 'nextPage'] // Simple pagination (no total count, faster) $paginator = $db->table('users') ->simplePaginate($page = 1, $perPage = 15); $hasMore = $paginator->hasMorePages();
INSERT Queries
// Single insert $affected = $db->table('users') ->insert([ 'name' => 'John Doe', 'email' => 'john@example.com', 'age' => 30 ]); // Bulk insert $affected = $db->table('users') ->insert([ ['name' => 'John', 'email' => 'john@example.com'], ['name' => 'Jane', 'email' => 'jane@example.com'], ['name' => 'Bob', 'email' => 'bob@example.com'] ]); // Insert and get ID $id = $db->table('users') ->insertGetId([ 'name' => 'John Doe', 'email' => 'john@example.com' ], 'id'); // Second parameter is the ID column name (default: 'id') // Insert or ignore (Pgsql: ON CONFLICT DO NOTHING, MySQL: INSERT IGNORE) $affected = $db->table('users') ->insertOrIgnore([ 'email' => 'john@example.com', 'name' => 'John Doe' ], ['email']); // Unique columns for conflict detection
UPSERT Queries
// MySQL: ON DUPLICATE KEY UPDATE // Pgsql: ON CONFLICT DO UPDATE // Upsert with auto-update of all non-unique columns $affected = $db->table('users') ->upsert( ['email' => 'john@example.com', 'name' => 'John Doe', 'age' => 30], ['email'], // Unique columns null // Update all non-unique columns ); // Upsert with specific columns to update $affected = $db->table('users') ->upsert( ['email' => 'john@example.com', 'name' => 'John Doe', 'age' => 30], ['email'], // Unique columns ['name', 'age'] // Columns to update on conflict ); // Bulk upsert $affected = $db->table('users') ->upsert( [ ['email' => 'john@example.com', 'name' => 'John'], ['email' => 'jane@example.com', 'name' => 'Jane'] ], ['email'], ['name'] );
UPDATE Queries
// Update with WHERE clause $affected = $db->table('users') ->where('id', 1) ->update([ 'name' => 'John Updated', 'email' => 'john.updated@example.com' ]); // Update multiple rows $affected = $db->table('users') ->where('status', 'pending') ->update(['status' => 'active']); // Update with JOIN $affected = $db->table('users') ->join('profiles', 'users.id', '=', 'profiles.user_id') ->where('profiles.verified', true) ->update(['users.status' => 'verified']); // Get generated SQL (for debugging) $sql = null; $affected = $db->table('users') ->where('id', 1) ->update(['name' => 'John'], $sql); echo $sql; // Outputs the generated SQL
DELETE Queries
// Delete with WHERE clause $affected = $db->table('users') ->where('status', 'deleted') ->delete(); // Delete with multiple conditions $affected = $db->table('users') ->where('status', 'inactive') ->where('last_login', '<', '2024-01-01') ->delete(); // Delete with JOIN $affected = $db->table('users') ->join('profiles', 'users.id', '=', 'profiles.user_id') ->where('profiles.banned', true) ->delete(); // Get generated SQL $sql = null; $affected = $db->table('users') ->where('id', 1) ->delete($sql);
Raw Expressions
use Craftix\Eloquent\Grammar\Expression; // Using raw expressions in queries $users = $db->table('users') ->select($db->raw('COUNT(*) as total')) ->get(); // Raw expressions in WHERE $users = $db->table('users') ->where($db->raw('DATE(created_at)'), '=', '2024-01-01') ->get(); // Raw expressions in JOIN $users = $db->table('users') ->join('profiles', $db->raw('users.id'), '=', $db->raw('profiles.user_id')) ->get(); // Or use Expression::make() $expr = Expression::make('NOW()'); $users = $db->table('users') ->where('created_at', '>', $expr) ->get();
Transactions
// Using DB instance $db->beginTransaction(); try { $db->table('users')->insert(['name' => 'John']); $db->table('profiles')->insert(['user_id' => 1, 'bio' => 'Bio']); $db->commit(); } catch (Exception $e) { $db->rollBack(); throw $e; } // Using transaction closure $db->transaction(function() use ($db) { $db->table('users')->insert(['name' => 'John']); $db->table('profiles')->insert(['user_id' => 1, 'bio' => 'Bio']); }); // Check if in transaction if ($db->inTransaction()) { // Currently in a transaction } // Using singleton DatabaseManager::beginTransaction(); try { DatabaseManager::table('users')->insert(['name' => 'John']); DatabaseManager::commit(); } catch (Exception $e) { DatabaseManager::rollBack(); } // Or with closure DatabaseManager::transaction(function() { DatabaseManager::table('users')->insert(['name' => 'John']); });
Working with Collections
All query results return a Collection instance with helpful methods:
$users = $db->table('users')->get(); // Collection methods $users->count(); // Get count $users->isEmpty(); // Check if empty $users->first(); // Get first item $users->last(); // Get last item $users->pluck('email'); // Get array of email values $users->plucked('email'); // Get new collection with emails // Filtering and mapping $users->filter(fn($user) => $user['age'] > 18); $users->map(fn($user) => strtoupper($user['name'])); // Searching $user = $users->find(fn($user) => $user['id'] === 1); $exists = $users->contains(['id' => 1]); // Array access $firstUser = $users[0]; $users[] = ['id' => 100, 'name' => 'New User']; // Convert to array/JSON $array = $users->toArray(); $json = $users->toJson();
Custom Object Conversion
// Convert results to custom objects $users = $db->table('users') ->objectConverter(function($row) { return new User($row); }) ->get(); // Now $users contains User objects instead of arrays foreach ($users as $user) { echo $user->getName(); }
Getting SQL Query
// Get the SQL query without executing $sql = $db->table('users') ->where('status', 'active') ->toSql(); echo $sql; // SELECT * FROM `users` WHERE `status` = :v1;
Database Dialects
The library automatically detects the database dialect, but you can also set it manually:
use Craftix\Eloquent\Grammar\Dialects\MySqlDialect; use Craftix\Eloquent\Grammar\Dialects\PostgresDialect; // Set MySQL dialect $db->setDialect(new MySqlDialect()); // Set Pgsql dialect $db->setDialect(new PostgresDialect());
π― API Reference
QueryBuilder Methods
Query Execution
get()- Execute SELECT and return Collectionfirst(...$columns)- Get first record (returns single value if one column, array if multiple)pluck($column)- Get single column as arraytoSql()- Get SQL string without executingpaginate($page, $perPage, $pageName = 'page')- Length-aware paginationsimplePaginate($page, $perPage, $pageName = 'page')- Simple pagination
Query Building
table($table)- Set table nameselect(...$columns)- Select columnsdistinct()- Add DISTINCTwhere($column, $operator, $value, $and = true)- Add WHERE conditionorWhere($column, $operator, $value)- Add OR WHERE conditionwhereIn($column, $values, $and = true)- WHERE INwhereNotIn($column, $values, $and = true)- WHERE NOT INwhereBetween($column, $value1, $value2, $and = true)- WHERE BETWEENwhereNotBetween($column, $value1, $value2, $and = true)- WHERE NOT BETWEENwhereNull($column, $and = true)- WHERE IS NULLwhereNotNull($column, $and = true)- WHERE IS NOT NULLwhereLike($column, $value, $and = true)- WHERE LIKEwhereNotLike($column, $value, $and = true)- WHERE NOT LIKEjoin($table, $column1, $operator, $column2, $type = 'INNER')- Add JOINleftJoin($table, $column1, $operator, $column2)- LEFT JOINrightJoin($table, $column1, $operator, $column2)- RIGHT JOINfullJoin($table, $column1, $operator, $column2)- FULL JOINorderBy($column, $type = 'ASC')- ORDER BYorderByDesc($column)- ORDER BY DESCinRandomOrder($seed = '')- Random orderlimit($limit)- LIMIToffset($offset)- OFFSET
Write Operations
insert($columnsToValues, &$resultedSql = null)- INSERTinsertGetId($columnsToValues, $idColumn = 'id', &$resultedSql = null)- INSERT and get IDinsertOrIgnore($columnsToValues, $uniqueColumns = null, &$resultedSql = null)- INSERT OR IGNOREupsert($columnsToValues, $uniqueBy, $updateOnDuplicate = null, &$resultedSql = null)- UPSERTupdate($columnsToValues, &$resultedSql = null)- UPDATEdelete(&$resultedSql = null)- DELETE
Utilities
raw($value)- Create raw SQL expressiongetValues()- Get bound parameter valuesobjectConverter($callback)- Set result object convertersetDialect($dialect)- Set SQL dialect
DB Class Methods
table($table)- Create QueryBuilder instancesetDialect($dialect)- Set dialectgetPdo()- Get PDO instancebeginTransaction()- Start transactioncommit()- Commit transactionrollBack()- Rollback transactioninTransaction()- Check if in transactiontransaction($callback)- Execute in transactionlastInsertId()- Get last insert IDexec($query, $params = null)- Execute raw SQLraw($value)- Create raw expression
Collection Methods
See the Collection documentation section above for available methods.
π Security
This library uses prepared statements with parameter binding by default, protecting against SQL injection attacks. Always use the query builder methods instead of raw SQL when possible.
// β Safe - Uses parameter binding $users = $db->table('users') ->where('email', $userEmail) ->get(); // β οΈ Only use raw expressions when absolutely necessary $users = $db->table('users') ->where($db->raw('email'), '=', $userEmail) // Still safe due to binding ->get();
π Error Handling
The library throws QueryBuilderException for query-related errors:
use Craftix\Eloquent\Data\QueryBuilderException; try { $users = $db->table('users')->get(); } catch (QueryBuilderException $e) { $errorCode = $e->getCode(); $message = $e->getMessage(); // Error codes: // 0 - Database execution error // 1000 - Invalid order type // 1001 - Invalid join type // 2000 - Missing table // 2001 - Missing columns // 2002 - Dangerous query (UPDATE/DELETE without WHERE) // 2004 - Invalid query }
π License
This project is licensed under the MIT License.
π€ Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
π§ Support
For issues, questions, or contributions, please visit the GitHub repository.
π Changelog
[1.1.0] - 2025-12-02
- Improved unit tests
- Added documentation for class methods and properties
[1.0.0] - 2025-11-15
- Initial release with core query builder and collection methods