Noga_SE is a modern, fluent, and immutable SQL QueryBuilder built in PHP 8.1+. It provides an elegant and secure API for building SELECT, INSERT, UPDATE, and DELETE queries with automatic parameter binding to prevent SQL injections.
- SELECT - Complex queries with joins, subqueries, aggregations, CTEs
- INSERT - Single and batch insertions with secure binding
- UPDATE - Safe updates with WHERE conditions
- DELETE - Protected deletions with conditions
- Parameter Binding - Automatic binding prevents SQL injections
- BindHashing - Cryptographically random parameter keys (
:prefix_hexrand_colname) - Immutability - Automatic cloning prevents mutations
- Type Safety - Strict type checking with exceptions
- Complex WHERE Clauses - AND, OR, LIKE, BETWEEN, IN, EXISTS, NOT IN
- Joins - INNER, LEFT, RIGHT, CROSS joins with multiple tables
- Subqueries - Nested queries via callables, Select instances, or strings
- Aggregations - GROUP BY, HAVING, COUNT, MAX, MIN, SUM, AVG
- Unions - UNION, UNION ALL for combining results
- CTEs - Common Table Expressions with recursive support
- Sorting & Pagination - ORDER BY, GROUP BY, LIMIT, OFFSET
- Query Caching - Reuse compiled queries efficiently
$query = Noga::table('users')
->select('id', 'name', 'email')
->where(['status' => 'active'])
->orderBy('created_at', 'DESC')
->limit(10);- Facade Pattern - Unified static API
- Builder Pattern - Chainable query construction
- Immutable Pattern - Safe object cloning
- Singleton Pattern - Single instances for managers
- Traits - Reusable functionality (conditions, aggregations)
- Clone the repository
- Configure autoloading in
composer.json:
{
"autoload": {
"psr-4": {
"Noga\\": "src/"
}
}
}use Noga\Noga;
$users = Noga::table('users')
->select('id', 'name', 'email')
->get();$activeUsers = Noga::table('users')
->select('*')
->where(['status' => 'active', 'age >=' => 18])
->get();$userPosts = Noga::table('users')
->select('users.name', 'posts.title')
->innerJoin(Noga::joins('posts', 'p')
->on('users.id', '=', 'p.user_id'))
->get();$topUsers = Noga::table('users')
->select('id', 'name')
->whereIn('id', fn($q) =>
$q->table('orders')
->select('user_id')
->where(['status' => 'completed'])
)
->get();$stats = Noga::table('orders')
->select('user_id', 'COUNT(*) as total_orders')
->groupBy(['user_id'])
->having(['total_orders >' => 5])
->get();$topUsers = Noga::table('users')
->select('*')
->orderBy('created_at', 'DESC')
->limit(10)
->offset(20)
->get();Executing mode :
->exec(); //interact with database
->getQuery(); //inspect Sql query string
->getValues(); //get all values
->viewState(); // show request use Noga\Noga;
$result = Noga::insert('users')
->columns('name', 'email', 'status')
->values('John Doe', 'john@example.com', 'active')
->exec(); //execute mode PDO $result = Noga::insert('users')
->from(__DIR__."/../membres.json")
->take() // obligatory
->viewState();
json format
// [
// {"id":"48","identifiant":"659225887","noms":"Noga","prenoms":"Germainio"},
// {"id":"48","identifiant":"659225887","noms":"Ephore","prenoms":"Miasa"},
// ....
// ]$debug = Noga::insert('users')
->columns('name', 'email')
->values('Test', 'test@example.com')
->viewState();
// output
// "sql": "INSERT INTO users( name,email ) VALUES(:in_c9f9f93a_name,:in_968abc56_email)",
// "params": {
// ":in_c9f9f93a_name": "Test",
// ":in_968abc56_email": "test@example.com"
// },
// "driver": "mysql",
// "table": "users",
// "columns": [
// "name",
// "email"
// ],
// "values": [
// "Test",
// "test@example.com"
// ],
// "binding": [
// ":in_c9f9f93a_name",
// ":in_968abc56_email"
// ]execution mode :
->exec(); //interact with database
->getQuery(); //inspect Sql query string
->getValues(); //get all values
->viewState(); // show request $result = Noga::update('users')
->set(['status' => 'active', 'updated_at' => 'NOW()'])
->where(['id' => 5])
->exec(); //PDO request$result = Noga::update("users")
->set(['verified' => true])
->where([
'email' => 'test@example.com',
'status' => 'inactive'
])
->exec();execution mode :
->exec(); //interact with database
->getQuery(); //inspect Sql query string
->getParams(); //get all params binding
->viewState(); // show request $result = Noga::delete('users')
->where(['id' => 1])
->exec();$result = Noga::delete('users')
->where(['status' => 'inactive', 'last_login <' => '2023-01-01'])
->limit(100)
->exec(); //PDO
// output with ->viewState();
// "Query": " DELETE FROM users
// WHERE status = :wh_c7e10fa3_status AND last_login < :wh_1878caa8_last_login
// LIMIT 100 ",
// "params": {
// ":wh_c7e10fa3_status": "inactive",
// ":wh_1878caa8_last_login": "2023-01-01"
// },
// "table": "users",
// "driver": "mysql"->select('id', 'name', 'email') // Specific columns
->select('*') // All columns
->distinct(true) // Remove duplicates
->selectCase(fn($case) =>$case->when("id","12")->else("25")->as("c"), 'status') // CASE WHEN expressions
//or
->selectCase(Noga::c("id","12")->else("25")->as("c"), 'status') ->where(['id' => 1, 'status' => 'active']) // AND condition
->whereOr(['status' => 'pending', 'status' => 'draft']) // OR condition
->whereLike(['name' => 'john']) // LIKE search
->whereIn('id', [1, 2, 3]) // IN clause
->whereNotIn('id', [10, 20]) // NOT IN clause
->whereBetween(['age' => [18, 65]]) // BETWEEN range
->whereColumn('created_at', '>', 'updated_at') // Column comparison
->isNull('deleted_at') // IS NULL
->isNotnull('verified_at') // IS NOT NULL
->whereExists(fn($q) => ...) // EXISTS subquery
->whereNotExists(fn($q) => ...) // NOT EXISTS->innerJoin(Noga::j('posts', 'p')
->on('users.id', '=', 'p.user_id'))
->leftJoin(Noga::j('comments', 'c')
->on('posts.id', '=', 'c.post_id'))
->rightJoin(Noga::j('categories', 'cat')
->on('posts.category_id', '=', 'cat.id'))
->crossJoin(Noga::j('departments', 'd'))->groupBy(['status', 'created_at'])
->having(['count >' => 5])->orderBy('created_at', 'DESC') // ASC or DESC
->limit(10) // Limit results
->offset(20) // Skip results//union simple
->union(Noga::u()->table('admins')->select('id', 'name'))
->unionAll(Noga::u()->table('moderators')->select('id', 'name'))
//union with table dynamique
->unionAll(Noga::u()->from(['admin','moderators'])->select('id','name'))
// union with a condition multiple
->unionAll(Noga::u()->add([
Noga::table("users")
->select("id","noms")
->where(["id"=>12])
])) ->with('recent_users',
fn($q) => $q->table('users')
->where(['created_at >' => 'NOW()'])
)
->with('category_tree',
fn($q) => $q->table('categories')
->select('id', 'name', 'parent_id')
->where(['parent_id' => null]),
true // Recursive
)->get() // All results as objects
->getOne() // Single row
->getStream() // Generator for large datasets
->getQuery() // Compiled SQL string
->getParams() // Bound parameters array
->viewState() // Complete request infosrc/
βββ Noga.php # Main Facade
βββ QueryBuilder/
β βββ builder.php # Clause construction
β βββ select/ # SELECT implementation
β βββ crud/ # INSERT, UPDATE, DELETE
βββ Core/
β βββ BindHashing.php # Secure parameter hashing
β βββ CacheManager.php # Query caching
β βββ Sqlast.php # SQL parsing & AST
β βββ NgManager.php # Configuration management
β βββ DateManager.php # Date formatting (FR/EN)
βββ Db/
β βββ DB.php # Database abstraction
β βββ mysql.php # MySQL driver
β βββ postgres.php # PostgreSQL driver
β βββ sqlite.php # SQLite driver
βββ Traits/
β βββ BuidlerAttr.php # Builder attributes
β βββ aggregate.php # Aggregation functions
β βββ condition.php # Condition building
β βββ dbTrait.php # Database connection
βββ helpers/
β βββ helpers.php # Utility functions
βββ CLI/
β βββ kernel.php # Command dispatcher
β βββ commands/ # Custom commands
βββ cache/ # Query cache storage
βββ exceptions/ # Custom exceptions
βββ mapping/ # Data mapping
// β UNSAFE - Vulnerable to SQL injection
$query = "SELECT * FROM users WHERE id = $id";
// β
SAFE - Parameters are bound
$query = Noga::table('users')
->where(['id' => $id]) // Automatically bound
->get();Parameter Key Generation:
Input: ['id' => 5, 'status' => 'active']
β BindHashing::hash()
Output:
:wh_a1b2c3d4_id => 5
:wh_e5f6g7h8_status => "active"
Each key is:
- Prefixed (:wh_ for WHERE)
- Random hex (a1b2c3d4)
- Column name
- Cryptographically secure
- Impossible to predict or inject
$base = Noga::table('users');
$active = $base->where(['status' => 'active']);
$admins = $base->where(['role' => 'admin']);
// $base, $active, $admins are 3 different objects
// No side effects or shared state# Unix/Linux/Mac
./noga test
# Windows
noga.bat testtest/NogaTest.php- PHPUnit test suitetest/test.php- Basic examplestest/users.php- User table examples
<!-- phpunit.xml -->
<phpunit bootstrap="vendor/autoload.php">
<testsuites>
<testsuite name="Builder SQL Suite">
<directory>./test</directory>
</testsuite>
</testsuites>
</phpunit>$results = Noga::table('orders')
->select(
'orders.id',
'orders.total',
'customers.name',
'COUNT(items.id) as item_count'
)
->innerJoin(Noga::joins('customers', 'c')
->on('orders.customer_id', '=', 'c.id'))
->innerJoin(Noga::joins('order_items', 'items')
->on('orders.id', '=', 'items.order_id'))
->where([
'orders.status' => 'completed',
'orders.created_at >=' => '2024-01-01'
])
->groupBy(['orders.id', 'customers.name'])
->having(['item_count >' => 3])
->orderBy('orders.total', 'DESC')
->limit(20)
->get();$hierarchy = Noga::table('categories')
->with('category_tree',
fn($q) => $q->table('categories')
->select('id', 'name', 'parent_id')
->where(['parent_id' => null]),
true // Recursive
)
->select('*')
->get();
//or
$hierarchy = Noga::table('categories')
->with('category_tree',
Noga::table('categories')
->select('id', 'name', 'parent_id')
->where(['parent_id' => null]),
true // Recursive
)
->select('*')
->get();// Register query
Noga::table('users')
->select('id', 'name')
->where(['status' => 'active'])
->add_query('get_active_users');
// Reuse from cache
$users = Noga::use_query('get_active_users')->get();
// Clear cache
Noga::removeCache('get_active_users');
Noga::removeAllCache();$analysis = Noga::explain(
Noga::table('users')
->select('*')
->where(['id' => 1]),
'FORMAT=JSON'
);Configure via NgManager or environment file:
// Initialize configuration
$config = NgManager::getInstance('path/to/ngconfig.ng');
// Access parameters
$host = ng('db_host');
$port = ng('db_port', 3306);CacheManager::key("my_query")
->dir("queries")
->delay(3600) // 1 hour
->data($result)
->put();β
Modern Web Applications - Build safe, fluent queries
β
API Development - Complex data retrieval with filters
β
Data Analysis - Aggregations, CTEs, subqueries
β
Reporting Systems - Multi-table joins and summaries
β
Admin Dashboards - Dynamic filtering and sorting
β
Microservices - Database abstraction layer
Contributions are welcome! Please follow these steps:
- Fork the project
- Create a feature branch (
git checkout -b feature/AmazingFeature) - Commit changes (
git commit -m 'Add some AmazingFeature') - Push to branch (
git push origin feature/AmazingFeature) - Open a Pull Request
# Clone repository
git clone https://github.com/nogagermainio/Noga_SE.git
cd Noga_SE
# Install dependencies
composer install
# Run tests
./noga test
# Check code
./noga lintThis project is licensed under the MIT License - see the LICENSE file for details.
MIT License
Copyright (c) 2026 nogagermainio
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions above.
nogagermainio
- GitHub: @nogagermainio
- Email: your-email@example.com
- Noga_Http - HTTP Framework companion
- Noga_CLI - Command-line interface tools
- PHP PDO Documentation
Found a bug? Want a feature? Please open an issue with:
- β Clear problem description
- β Minimal code reproduction
- β Expected vs actual behavior
- β PHP version and OS
Q: How do I prevent SQL injection?
A: All parameters are automatically bound via BindHashing. Never concatenate user input!
Q: Can I cache queries?
A: Yes! Use ->add_query('name') and Noga::use_query('name')
Q: Is it compatible with my database?
A: Noga_SE supports MySQL, PostgreSQL, SQLite, and is easily extended for others.
Q: How do I contribute?
A: Fork the repo, create a feature branch, and submit a pull request.
- SELECT with advanced clauses
- INSERT with secure binding
- UPDATE with conditions
- DELETE with protection
- Joins (INNER, LEFT, RIGHT, CROSS)
- Subqueries & nesting
- Unions & intersections
- Recursive CTEs
- Immutability & cloning
- Query caching
- Enhanced error reporting
- Performance profiling
- Query optimization hints
- Additional database drivers
- Trigger & stored procedure support
- Database schema builders
- Migration system
- Query logging middleware
- Batch optimization
- Full-text search support
-
Use Pagination - Limit large result sets
->limit(20)->offset($page * 20)
-
Cache Frequently Used Queries - Reuse compiled queries
->add_query('active_users')
-
Use Indexes - Create database indexes on WHERE columns
CREATE INDEX idx_status ON users(status);
-
Batch Operations - Insert multiple rows at once
->values(...)->values(...)->values(...)
-
Select Only Needed Columns - Avoid SELECT *
->select('id', 'name', 'email') // Not SELECT *
- π¬ GitHub Discussions
- π Issue Tracker
- π Wiki & Documentation
If you find Noga_SE helpful, please consider:
- β Star the repository
- π΄ Fork and contribute
- π’ Share with your network
- π¬ Leave feedback
Made with β€οΈ by nogagermainio
Last updated: 2026-07-01
Version: 1.0.0