herdianrony / bangrondb
SQLite-based NoSQL document database with MongoDB-like API, encryption, hooks, relationships, and enterprise features
Requires
- php: >=8.0
Requires (Dev)
- phpunit/phpunit: ^9.6
This package is auto-updated.
Last update: 2026-02-13 18:08:26 UTC
README
📖 Daftar Isi
- Overview
- Instalasi
- Konsep Dasar
- Client & Database
- Collection
- Schema Validation
- Soft Deletes
- Operasi CRUD
- Query & Filtering
- Encryption & Security
- Searchable Fields
- Hooks & Events
- Populate & Relationships
- Indexing
- Health & Monitoring
- Change Notification
- Dynamic Configuration
- Utilities
- Examples
- Enterprise Readiness
- Performa & Benchmark
📋 Overview
BangronDB adalah database NoSQL berbasis SQLite dengan API mirip MongoDB, yang dibangun untuk PHP. Mendukung enkripsi, hook, relasi, dan fitur enterprise lainnya.
Fitur Utama:
- API MongoDB-like - Sintaks familiar seperti MongoDB
- Enkripsi AES-256 - Enkripsi tingkat kolom dan koleksi
- Searchable Fields - Pencarian pada data terenkripsi
- Hooks System - Event-driven hooks untuk semua operasi
- Relationships - Populate untuk relasi antar koleksi
- Multiple ID Modes - UUID, manual, dan prefiks
- Health Monitoring - Monitoring dan metrics database
- SQLite Backend - Performa tinggi dengan ACID compliance
🚀 Instalasi
Persyaratan
- PHP 8.0+ dengan ekstensi PDO SQLite
- Ekstensi OpenSSL untuk enkripsi
- Composer (Direkomendasikan)
Instalasi via Composer
composer require herdianrony/BangronDB
Instalasi Manual
Jika tidak menggunakan Composer, include file secara manual:
<?php // Sertakan semua file yang diperlukan require_once __DIR__ . '/src/Client.php'; require_once __DIR__ . '/src/Database.php'; require_once __DIR__ . '/src/Collection.php'; require_once __DIR__ . '/src/Cursor.php'; require_once __DIR__ . '/src/UtilArrayQuery.php'; // Sertakan traits require_once __DIR__ . '/src/Traits/EncryptionTrait.php'; require_once __DIR__ . '/src/Traits/HooksTrait.php'; require_once __DIR__ . '/src/Traits/IdGeneratorTrait.php'; require_once __DIR__ . '/src/Traits/QueryBuilderTrait.php'; require_once __DIR__ . '/src/Traits/SchemaValidationTrait.php'; require_once __DIR__ . '/src/Traits/SearchableFieldsTrait.php'; require_once __DIR__ . '/src/Traits/SoftDeleteTrait.php'; // Sekarang Anda dapat menggunakan BangronDB use BangronDB\Client;
Struktur Namespace
use BangronDB\Client; use BangronDB\Database; use BangronDB\Collection; use BangronDB\Cursor;
⚡ Quick Start (5 Menit)
use BangronDB\Client; // 1. Inisialisasi (Data disimpan di folder 'data') $client = new Client(__DIR__ . '/data'); // 2. Pilih database & collection $users = $client->app->users; // 3. Simpan data (Otomatis buat ID) $userId = $users->insert([ 'name' => 'John Doe', 'role' => 'admin' ]); // 4. Cari data $user = $users->findOne(['name' => 'John Doe']); echo "Halo, " . $user['name'];
🏗️ Konsep Dasar
BangronDB menyimpan data dalam format JSON (seperti file teks yang terstruktur) di dalam database SQLite. Ini memberikan fleksibilitas NoSQL dengan ketangguhan database relasional.
Arsitektur
graph TD
A[Client] -->|mengelola| B[Database File]
B -->|berisi| C[Collection / Tabel]
C -->|menyimpan| D[Document / JSON]
subgraph "Storage Layer"
B
end
Loading
Hierarki Data
- Client: Manager utama yang mengatur koneksi ke berbagai database.
- Database: Satu file fisik
.bangrondi komputer Anda. - Collection: "Folder" di dalam database untuk mengelompokkan data sejenis (misal: users, products).
- Document: Satu record data dalam format array/JSON.
🔌 Client & Database
Inisialisasi Client
use BangronDB\Client; // Database file-based $client = new Client(__DIR__ . '/data'); // Database in-memory $client = new Client(':memory:'); // Dengan options $options = [ 'encryption_key' => 'my-secret-key', 'timeout' => 30 ]; $client = new Client(__DIR__ . '/data', $options);
Mengakses Database
// Method chaining $db = $client->selectDB('mydatabase'); $collection = $db->selectCollection('users'); // Magic getter $db = $client->mydatabase; $collection = $db->users; // Langsung ke collection $collection = $client->selectCollection('mydatabase', 'users');
Operasi Database
// List databases $databases = $client->listDBs(); // ['db1', 'db2'] // Health metrics $metrics = $db->getHealthMetrics(); $report = $db->getHealthReport(); // Cleanup $client->close(); Database::closeAll();
📦 Collection
Inisialisasi Collection
$collection = $db->selectCollection('users'); // atau $collection = $db->users;
Konfigurasi Collection
// Set ID generation mode $collection->setIdModeAuto(); // UUID v4 (default) $collection->setIdModeManual(); // Manual ID $collection->setIdModePrefix('USR'); // Prefiks: USR-000001 // Enkripsi per koleksi $collection->setEncryptionKey('collection-secret-key'); // Searchable fields $collection->setSearchableFields(['email', 'phone'], true); // true untuk hashing // Drop collection $collection->drop(); // Rename collection $success = $collection->renameCollection('new_name'); // Returns true/false
ID Generation Modes
// Auto (UUID v4) - default // Contoh: "550e8400-e29b-41d4-a716-446655440000" // Manual - harus menyediakan _id manual $collection->setIdModeManual(); // Prefix - auto increment dengan prefiks $collection->setIdModePrefix('USR'); // Contoh: "USR-000001", "USR-000002"
📝 Operasi CRUD
Create (Insert)
// Insert single document $id = $collection->insert([ 'name' => 'John Doe', 'email' => 'john@example.com', 'age' => 30 ]); // Insert multiple documents (batch insert) $count = $collection->insert([ ['name' => 'Alice', 'age' => 25], ['name' => 'Bob', 'age' => 35] ]); // Returns number of inserted documents // Insert dengan ID manual (mode manual) $collection->setIdModeManual(); $id = $collection->insert([ '_id' => 'custom-id-123', 'name' => 'Custom User' ]);
Read (Find)
// Find all documents $cursor = $collection->find(); $users = $cursor->toArray(); // Find one document $user = $collection->findOne(['name' => 'John']); // Find dengan criteria $cursor = $collection->find([ 'age' => ['$gt' => 25], 'status' => 'active' ]); // Dengan projection (field selection) $cursor = $collection->find( ['age' => ['$gte' => 21]], ['name' => 1, 'email' => 1] // Hanya ambil name dan email ); // Count documents $count = $collection->count(['status' => 'active']);
Update
// Update dengan merge (default) $updated = $collection->update( ['name' => 'John Doe'], // Criteria ['age' => 31, 'city' => 'NY'] // Data baru ); // Hasil: {name: 'John Doe', email: 'john@example.com', age: 31, city: 'NY'} // Update tanpa merge (replace) $updated = $collection->update( ['name' => 'John Doe'], ['age' => 31], false // Non-merge mode ); // Hasil: {_id: '...', age: 31} // field lain hilang // MongoDB-style Updates dengan $set dan $unset $collection->update( ['name' => 'John Doe'], [ '$set' => ['age' => 31, 'city' => 'NY'], // Set fields '$unset' => ['old_field' => ''] // Remove fields ] ); // Hasil: {name: 'John Doe', email: 'john@example.com', age: 31, city: 'NY'} // Kombinasi merge dan MongoDB-style $collection->update( ['name' => 'John Doe'], [ 'status' => 'active', // Merge field '$set' => ['last_login' => date('c')], // Set field '$unset' => ['temp_password' => ''] // Remove field ] ); // Upsert dengan save() - Insert jika belum ada, Update jika sudah ada $collection->save([ '_id' => 'existing-id', 'name' => 'Updated Name' ]); // Akan update jika _id sudah ada, atau insert jika belum ada
Delete
// Remove documents $deleted = $collection->remove(['status' => 'inactive']); // Remove semua documents $collection->remove([]);
Pagination & Sorting
$cursor = $collection->find(['status' => 'active']) ->skip(10) // Skip 10 dokumen ->limit(5) // Ambil 5 dokumen ->sort(['age' => 1]); // Sort ascending // Sort descending $cursor->sort(['age' => -1]);
🔍 Query & Filtering
Operators yang Didukung
// Comparison operators $collection->find(['age' => ['$gt' => 18]]); $collection->find(['age' => ['$gte' => 21]]); $collection->find(['age' => ['$lt' => 65]]); $collection->find(['age' => ['$lte' => 60]]); $collection->find(['age' => ['$ne' => 30]]); // Array operators $collection->find(['role' => ['$in' => ['admin', 'editor']]]); $collection->find(['role' => ['$nin' => ['guest', 'banned']]]); // Existence operator $collection->find(['email' => ['$exists' => true]]); // Logical operators $collection->find([ '$or' => [ ['age' => ['$lt' => 18]], ['age' => ['$gt' => 65]] ] ]); $collection->find([ '$and' => [ ['status' => 'active'], ['age' => ['$gte' => 21]] ] ]); // Regex matching $collection->find(['name' => ['$regex' => '^John']]); // Custom function $collection->find([ 'custom_field' => [ '$func' => function($value) { return strlen($value) > 5; } ] ]); // Fuzzy search $collection->find([ 'description' => [ '$fuzzy' => [ '$search' => 'important document', '$minScore' => 0.7, '$distance' => 3 ] ] ]);
Dot Notation untuk Nested Fields
// Query nested fields $collection->find(['address.city' => 'New York']); // Update nested fields $collection->update( ['_id' => '123'], ['address.city' => 'Los Angeles'] );
Custom Query Functions
// PHP callback sebagai criteria $result = $collection->find(function($document) { return $document['age'] > 18 && strpos($document['email'], '@gmail.com') !== false; });
🔐 Encryption & Security
Database-wide Encryption
// Set encryption key di level database $db = new Database('path/to/db.sqlite', [ 'encryption_key' => 'master-secret-key' ]);
Collection-specific Encryption
// Override encryption key per collection $collection->setEncryptionKey('collection-specific-key'); // Cek status enkripsi $isEncrypted = $collection->isEncrypted(); // true/false
Format Data Terenkripsi
{
"_id": "550e8400-e29b-41d4-a716-446655440000",
"encrypted_data": "base64-encrypted-string",
"iv": "base64-initialization-vector"
}
Algorithm Details
- Algorithm: AES-256-CBC
- Key Derivation: SHA-256 hashing
- IV: Random bytes per encryption
- Storage: Base64 encoded dalam JSON
🔎 Searchable Fields
Konfigurasi Searchable Fields
// Tambah searchable fields dengan hashing $collection->setSearchableFields(['email', 'phone'], true); // Hashed: si_email = sha256(email), si_phone = sha256(phone) // Tanpa hashing (plain text) $collection->setSearchableFields(['name', 'city'], false); // Plain: si_name = "John Doe", si_city = "New York" // Nested fields support $collection->setSearchableFields(['address.zip'], false); // Remove searchable field $collection->removeSearchableField('email', true); // true untuk drop column
Cara Kerja
- Column Naming:
si_{fieldname}(si = searchable index) - Hashing: Opsional SHA-256 untuk privacy
- Query Optimization: Menggunakan column langsung bukan json_extract
- Auto-maintenance: Columns dibuat/dihapus otomatis
Contoh Query dengan Searchable Fields
// Query akan otomatis menggunakan column si_email jika ada $users = $collection->find(['email' => 'john@example.com']); // Untuk hashed fields, value otomatis di-hash $collection->find(['email' => 'john@example.com']); // Diterjemahkan ke: WHERE si_email = sha256('john@example.com')
🎣 Hooks & Events
Event yang Tersedia
Collection::HOOK_BEFORE_INSERT // Sebelum insert Collection::HOOK_AFTER_INSERT // Setelah insert Collection::HOOK_BEFORE_UPDATE // Sebelum update Collection::HOOK_AFTER_UPDATE // Setelah update Collection::HOOK_BEFORE_REMOVE // Sebelum delete Collection::HOOK_AFTER_REMOVE // Setelah delete
Registrasi Hooks
// Before insert hook $collection->on('beforeInsert', function($document) { // Validasi atau modifikasi data if (!isset($document['created_at'])) { $document['created_at'] = date('Y-m-d H:i:s'); } return $document; // Return modified document }); // After insert hook $collection->on('afterInsert', function($document, $insertId) { // Logging atau side effects error_log("Document inserted: " . $insertId); }); // Before update hook $collection->on('beforeUpdate', function($criteria, $data) { // Modifikasi criteria atau data $data['updated_at'] = date('Y-m-d H:i:s'); return ['criteria' => $criteria, 'data' => $data]; }); // Veto operation dengan return false $collection->on('beforeRemove', function($document) { if ($document['protected'] ?? false) { return false; // Cancel removal } }); // Remove hooks $collection->off('beforeInsert'); // Remove all beforeInsert hooks $collection->off('beforeInsert', $specificCallback); // Remove specific
Hook Return Values
// Return array: Modifikasi data return ['field' => 'new value']; // Return false: Batalkan operasi return false; // Return true/null: Lanjutkan tanpa perubahan return true;
🔗 Populate & Relationships
Basic Populate
// Collection users $users = $db->users; // Collection posts $posts = $db->posts; // Posts memiliki author_id yang merujuk ke users._id $postsWithAuthors = $posts->find() ->populate('author_id', $users, ['as' => 'author']) ->toArray(); // Hasil: post['author'] berisi user document
Nested Populate
// Populate multiple levels $posts = $db->posts->find() ->populate('author_id', $db->users, ['as' => 'author']) ->populate('category_id', $db->categories, ['as' => 'category']) ->toArray();
Array References
// Post memiliki array of comment IDs $post = $db->posts->findOne(['_id' => 'post123']); $postWithComments = $db->posts->populate( $post, 'comment_ids', // Field berisi array of IDs 'db.comments', // Target collection '_id', // Foreign field 'comments' // Alias untuk hasil );
Cross-Database Populate
// Populate dari database berbeda $collection->populate( $documents, 'foreign_field', 'otherdb.othercollection', // Format: database.collection '_id', 'relation' );
📊 Indexing
JSON Field Index
// Buat index untuk field JSON $collection->createIndex('email'); $collection->createIndex('address.city'); $collection->createIndex('status', 'idx_status'); // Hasil SQL: CREATE INDEX idx_users_email ON users(json_extract(document, '$.email'))
Drop Index
$db->dropIndex('idx_email');
Best Practices
// Index fields yang sering di-query $collection->createIndex('email'); $collection->createIndex('created_at'); $collection->createIndex(['status', 'created_at']); // Index untuk searchable fields otomatis optimal
🔄 Change Notification
Pengantar Change Notification
BangronDB menyediakan sistem change notification untuk melacak perubahan pada collection. Setiap kali dokumen ditambahkan, diupdate, atau dihapus, sistem akan mencatat versi dan timestamp terakhir.
Metadata Table
Setiap database memiliki tabel _collection_metadata yang mencatat:
CREATE TABLE _collection_metadata ( collection_name TEXT PRIMARY KEY, version INTEGER DEFAULT 0, last_updated TIMESTAMP DEFAULT CURRENT_TIMESTAMP )
Mendapatkan Informasi Perubahan
$collection = $db->users; // Dapatkan versi dan timestamp terakhir $lastModified = $collection->getLastModified(); // Output: [ 'version' => 42, 'last_updated' => '2024-01-15 10:30:45' ]
Change Tracking
Sistem otomatis melacak perubahan pada operasi berikut:
insert()- Menambah dokumen baruupdate()- Mengupdate dokumen existingremove()- Menghapus dokumen (hard delete)forceDelete()- Menghapus dokumen (bypass soft delete)
Implementasi Manual Change Tracking
Untuk operasi kustom, Anda bisa memanggil notifyChange() secara manual:
// Setelah operasi kustom $collection->notifyChange();
Use Cases
- Cache Invalidation: Invalidate cache ketika data berubah
- Audit Trail: Track kapan collection terakhir diubah
- Sync Mechanisms: Sinkronisasi data antar sistem
- Monitoring: Monitor aktivitas database
// Contoh: Cache invalidation berdasarkan versi class CacheManager { private $cache = []; private $versions = []; public function getUsers(Collection $users) { $lastModified = $users->getLastModified(); $key = 'users_data'; if (!isset($this->versions[$key]) || $this->versions[$key]['version'] !== $lastModified['version']) { // Data berubah, fetch ulang $this->cache[$key] = $users->find()->toArray(); $this->versions[$key] = $lastModified; } return $this->cache[$key]; } }
🩺 Health & Monitoring
Health Metrics
$metrics = $db->getHealthMetrics(); // Struktur metrics: [ 'database' => [ 'path' => '...', 'type' => 'file|memory', 'encryption_enabled' => true/false ], 'integrity' => [ 'status' => 'healthy|corrupted|error', 'details' => [...] ], 'metrics' => [ 'total_collections' => 5, 'total_documents' => 1000, 'total_size_bytes' => 5242880, 'collections' => [ 'users' => [ 'documents' => 500, 'size_bytes' => 2621440, 'avg_document_size' => 5242.88 ] ] ], 'performance' => [ 'page_count' => 1280, 'page_size' => 4096, 'fragmentation_ratio' => 0.05, 'indexes' => [...] ], 'collections' => [ 'users' => [ 'documents' => 500, 'encryption_enabled' => true, 'id_mode' => 'auto', 'searchable_fields' => ['email', 'phone'], 'hooks' => [ 'beforeInsert' => 2, 'afterInsert' => 1, // ... ] ] ] ]
Health Report
$report = $db->getHealthReport(); // Struktur report: [ 'status' => 'healthy|warning|critical', 'issues' => ['Database integrity check failed'], 'warnings' => ['High fragmentation detected'], 'recommendations' => ['Run VACUUM command'], 'timestamp' => '2024-01-15T10:30:00+00:00' ]
Maintenance Commands
// Reclaim space $db->vacuum(); // Check integrity $integrity = $db->checkIntegrity(); // Get performance metrics $perf = $db->getPerformanceMetrics(); // Get collection metrics $collMetrics = $db->getCollectionMetrics();
🛠️ Utilities
Criteria Functions
// Register custom criteria function $criteriaId = $db->registerCriteriaFunction(function($doc) { return $doc['active'] === true && $doc['age'] >= 18; }); // Gunakan di query $results = $collection->find($criteriaId);
Array Query Utilities
use BangronDB\UtilArrayQuery; // Match document terhadap criteria $matches = UtilArrayQuery::match( ['age' => ['$gt' => 18], 'status' => 'active'], $document ); // Generate UUID $uuid = UtilArrayQuery::generateId(); // Fuzzy search $score = UtilArrayQuery::fuzzy_search('search term', 'text to search', 3);
Transaction Support
// Manual transaction $db->connection->beginTransaction(); try { $collection->insert($doc1); $collection->insert($doc2); $db->connection->commit(); } catch (\Exception $e) { $db->connection->rollBack(); throw $e; }
Batch Operations
// Insert many dalam transaction $collection->insert([ ['name' => 'User1'], ['name' => 'User2'], ['name' => 'User3'] ]); // Update banyak dokumen $collection->update( ['status' => 'pending'], ['status' => 'processed', 'processed_at' => date('Y-m-d H:i:s')] );
⚠️ Error Handling
Common Exceptions
try { $collection->insert($document); } catch (\InvalidArgumentException $e) { // Invalid arguments (nama database/collection, dll) } catch (\RuntimeException $e) { // Runtime errors (encryption failures, dll) } catch (\PDOException $e) { // Database errors } catch (\Throwable $e) { // All other errors }
Debugging
// Enable error reporting error_reporting(E_ALL); ini_set('display_errors', 1); // Check last SQL error $errorInfo = $db->connection->errorInfo(); // Log operations $collection->on('afterInsert', function($doc, $id) { error_log("Inserted: " . json_encode($doc)); });
📈 Best Practices
1. ID Strategy
// Use UUID untuk distributed systems $collection->setIdModeAuto(); // Use prefix untuk human-readable IDs $collection->setIdModePrefix('USR'); // Manual IDs untuk migrations $collection->setIdModeManual();
2. Encryption Strategy
// Master key untuk semua collections $db = new Database('path.sqlite', [ 'encryption_key' => 'master-key-here' ]); // Per-collection key untuk sensitive data $sensitiveCollection->setEncryptionKey('strong-key-here'); $sensitiveCollection->setSearchableFields(['email'], true);
3. Performance Optimization
// Create indexes untuk frequent queries $collection->createIndex('email'); $collection->createIndex('created_at'); // Use searchable fields untuk encrypted search $collection->setSearchableFields(['email', 'phone'], true); // Batch operations untuk bulk data $collection->insertMany($largeDataset); // Pagination untuk large result sets $cursor = $collection->find()->limit(100)->skip(0);
4. Data Modeling
// Denormalize untuk read performance $userWithPosts = [ '_id' => 'user123', 'name' => 'John', 'recent_posts' => [/* embed 5 most recent posts */] ]; // Reference untuk consistency $post = [ '_id' => 'post123', 'author_id' => 'user123', 'title' => 'Hello World' ]; // Use populate untuk relationships $posts = $db->posts->find() ->populate('author_id', $db->users) ->toArray();
🔧 Migration & Backup
Backup Database
// File-based backup copy('/path/to/database.sqlite', '/backup/database-backup.sqlite'); // In-memory to file backup $client = new Client(':memory:'); // ... operations ... // Export to file melalui attach
Data Migration
// Migrate dari collection lama ke baru $oldCollection = $db->old_users; $newCollection = $db->users; $cursor = $oldCollection->find(); foreach ($cursor as $doc) { // Transform data $doc['migrated_at'] = date('Y-m-d H:i:s'); $newCollection->insert($doc); }
🎯 Contoh Lengkap Aplikasi
Sistem User Management
<?php require 'vendor/autoload.php'; use BangronDB\Client; // Setup database $client = new Client(__DIR__ . '/data', [ 'encryption_key' => 'supersecret123' ]); $db = $client->selectDB('myapp'); $users = $db->users; // Configure collection $users->setIdModePrefix('USR'); $users->setEncryptionKey('user-encryption-key'); $users->setSearchableFields(['email', 'username'], true); // Schema validation $users->setSchema([ 'username' => ['required' => true, 'type' => 'string', 'min' => 3, 'max' => 50], 'email' => ['required' => true, 'type' => 'string', 'regex' => '/^[^\s@]+@[^\s@]+\.[^\s@]+$/'], 'age' => ['type' => 'int', 'min' => 13, 'max' => 120], 'role' => ['type' => 'string', 'enum' => ['admin', 'user', 'moderator']] ]); // Enable soft deletes $users->useSoftDeletes(true); // Hooks $users->on('beforeInsert', function($doc) { $doc['created_at'] = date('Y-m-d H:i:s'); $doc['updated_at'] = $doc['created_at']; return $doc; }); $users->on('beforeUpdate', function($criteria, $data) { $data['updated_at'] = date('Y-m-d H:i:s'); return ['criteria' => $criteria, 'data' => $data]; }); // Create user $userId = $users->insert([ 'username' => 'johndoe', 'email' => 'john@example.com', 'password' => password_hash('secret123', PASSWORD_DEFAULT), 'role' => 'user', 'status' => 'active' ]); // Find user $user = $users->findOne([ 'email' => 'john@example.com', 'status' => 'active' ]); // Update user $users->update( ['_id' => $userId], ['last_login' => date('Y-m-d H:i:s')] ); // Query dengan pagination $activeUsers = $users->find(['status' => 'active']) ->sort(['created_at' => -1]) ->limit(20) ->skip(0) ->toArray(); // Health check $health = $db->getHealthReport(); if ($health['status'] !== 'healthy') { error_log('Database issues: ' . json_encode($health['issues'])); } // Soft delete example $deletedCount = $users->remove(['username' => 'johndoe']); // Soft delete $allUsers = $users->find()->withTrashed()->toArray(); // Include deleted $onlyDeleted = $users->find()->onlyTrashed()->toArray(); // Only deleted $activeUsers = $users->find()->toArray(); // Only active $restoredCount = $users->restore(['username' => 'johndoe']); // Restore $permanentDelete = $users->forceDelete(['username' => 'johndoe']); // Permanent delete // Change notification $changeInfo = $users->getLastModified(); echo "Users collection last modified: {$changeInfo['last_updated']} (version {$changeInfo['version']})"; // Cleanup $client->close();
📚 API Reference Summary
Client Methods
__construct($path, $options = [])listDBs()- List semua databaseselectDB($name)- Pilih databaseselectCollection($database, $collection)- Pilih collection langsungclose()- Tutup semua koneksi
Database Methods
__construct($path, $options = [])selectCollection($name)- Pilih collectioncreateCollection($name)- Buat collection barudropCollection($name)- Hapus collectiongetCollectionNames()- List semua collectioncreateJsonIndex($collection, $field, $indexName = null)- Buat indexattach($path, $alias)- Attach database laindetach($alias)- Detach databasevacuum()- Optimasi databasegetHealthMetrics()- Ambil metrics kesehatangetHealthReport()- Ambil health reportsaveCollectionConfig($collectionName, $config)- Simpan konfigurasi collectionloadCollectionConfig($collectionName)- Load konfigurasi collectiongetAllCollectionConfigs()- Load semua konfigurasi collectiondeleteCollectionConfig($collectionName)- Hapus konfigurasi collection
Collection Methods
__construct($name, $database)setIdModeAuto(),setIdModeManual(),setIdModePrefix($prefix)setEncryptionKey($key)- Set encryption key (harus dipanggil saat runtime)isEncrypted()- Cek apakah encryption enabledsetSearchableFields($fields, $hash = false)- Konfigurasi searchable fieldssetSchema($schema)- Set schema validation rulesgetSchema()- Get schema validation rulesvalidate($document)- Validate document against schemauseSoftDeletes($enabled = true)- Enable/disable soft deletessoftDeletesEnabled()- Check if soft deletes enabledgetDeletedAtField()- Get soft delete field namerestore($criteria)- Restore soft-deleted documentsforceDelete($criteria)- Permanently delete documentsgetLastModified()- Get collection change infonotifyChange()- Notify collection changesetCustomConfig($key, $value)- Set custom config valuegetCustomConfig($key, $default = null)- Get custom config valuegetAllCustomConfig()- Get all custom config valuessetCustomConfigArray($config)- Set multiple custom config valuesinsert($document)- Insert documentinsertMany($documents)- Insert banyak documentsfind($criteria = null, $projection = null)- Cari documentsfindOne($criteria = null, $projection = null)- Cari satu documentupdate($criteria, $data, $merge = true)- Update documentsremove($criteria)- Hapus documentscount($criteria = null)- Hitung documentssave($document, $create = false)- Save/upsert documentdrop()- Hapus collectionrenameCollection($newname)- Rename collectionpopulate($documents, $localField, $foreign, $foreignField = '_id', $as = null)- Populate relasion($event, $fn)- Register hookoff($event, $fn = null)- Remove hookcreateIndex($field, $indexName = null)- Buat indexrenameCollection($newName)- Rename collectionnotifyChange()- Notify collection change (internal)getLastModified()- Get collection change infoloadConfiguration()- Load konfigurasi dari database (internal)saveConfiguration()- Simpan konfigurasi ke databaseforceDelete($criteria)- Permanently delete documents (bypass soft delete)
Cursor Methods
__construct($collection, $criteria, $projection = null)count()- Hitung hasil querylimit($limit)- Set limitskip($skip)- Set skipsort($sort)- Set sort orderpopulate($path, $collection, $options = [])- Populate relasiwithTrashed()- Include soft-deleted documents (soft delete)onlyTrashed()- Return only soft-deleted documents (soft delete)toArray()- Konversi ke arrayeach($callable)- Iterasi tiap document
🔄 Changelog & Migrasi
Versi 1.0 Features:
- MongoDB-like API
- AES-256 encryption
- Searchable encrypted fields
- Hooks system
- Relationship population
- Multiple ID generation modes
- Health monitoring
- Transaction support
- JSON query operators
- Cross-database operations
- 🧩 Modular Architecture: Refactored into traits for better maintainability and extensibility.
- ✅ Schema Validation: Built-in rules for data integrity (types, enums, regex, ranges).
- 🗑️ Soft Deletes: Logic-based deletion with
withTrashed()andrestore()support. - 🔄 MongoDB-style Updates: Support for
$setand$unsetoperators. - 🔒 Encrypted Storage: Documents are encrypted at rest using AES-256-CBC with per-collection granularity.
Breaking Changes:
- Cache Removal: In-memory cache dihapus untuk menghindari memory leak
- Encryption Format: Format enkripsi berubah untuk support searchable fields
- Hook API: Hook return values lebih strict
Migration dari Versi Lama:
// Old: Cache operations $collection->flushCache(); // Tidak diperlukan lagi // Old: Simple encryption // New: Encryption dengan searchable fields support $collection->setEncryptionKey('key'); $collection->setSearchableFields(['email'], true); // Old: Hook return values // New: Return false untuk cancel, array untuk modify
🆘 Pemecahan Masalah
Common Issues:
-
Encryption Errors
Problem: Cannot decrypt stored document Solution: Pastikan encryption key sama dengan yang digunakan saat insert -
Searchable Fields Not Working
Problem: Query tidak menggunakan searchable columns Solution: Pastikan setSearchableFields() dipanggil sebelum insert -
Performance Issues
Problem: Query lambat Solution: Buat index dengan createIndex(), gunakan searchable fields -
Memory Issues
Problem: Memory leak pada large datasets Solution: Gunakan cursor dengan limit(), hindari toArray() pada data besar
Debug Mode:
// Enable PDO exceptions $db->connection->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION); // Log semua operations $collection->on('afterInsert', function($doc, $id) { error_log("INSERT: " . $id); }); $collection->on('afterUpdate', function($old, $new) { error_log("UPDATE: " . $new['_id']); });
📞 Dukungan & Sumber Daya
Getting Help:
- Issues: Check error messages dan PHP logs
- Debugging: Enable PDO exception mode
- Community: PHP developer forums
Additional Resources:
- SQLite Documentation: https://www.sqlite.org/docs.html
- PDO Documentation: https://www.php.net/manual/en/book.pdo.php
- MongoDB Query Reference: https://docs.mongodb.com/manual/reference/operator/query/
Performance Tips:
- Gunakan transaction untuk bulk operations
- Buat index untuk frequent queries
- Gunakan searchable fields untuk encrypted search
- Implement pagination untuk large datasets
- Monitor dengan health metrics regularly
🤝 Contributing
Kami menyambut kontribusi dari komunitas! Berikut adalah cara berkontribusi:
Cara Berkontribusi
- Fork repositori ini
- Buat branch untuk fitur/fix Anda (
git checkout -b feature/AmazingFeature) - Commit perubahan (
git commit -m 'Add some AmazingFeature') - Push ke branch (
git push origin feature/AmazingFeature) - Buat Pull Request
Panduan Kontribusi
- Pastikan kode Anda mengikuti PSR-12 coding standard
- Tambahkan test untuk fitur baru
- Update dokumentasi jika diperlukan
- Gunakan conventional commits
Melaporkan Bug
Gunakan issue tracker untuk melaporkan bug. Sertakan:
- Deskripsi lengkap masalah
- Langkah reproduksi
- Versi PHP dan sistem operasi
- Stack trace jika ada
🌟 Modern Fullstack Example (Flight + Latte)
Kami menyediakan contoh dashboard modern yang menggunakan Flight PHP (Micro-framework) dan Latte (Template Engine).
Fitur Dashboard:
- Glassmorphism UI: Tampilan premium dengan dark mode.
- Real-time feel: Manajemen tugas dan pesan tim.
- Flight PHP Integration: API dan routing yang bersih.
- Latte Templates: Keamanan dan kemudahan templating.
Cara Menjalankan:
- Masuk ke folder contoh:
cd examples/modern_dashboard - Jalankan server lokal:
php -S localhost:8000 - Bukalah
http://localhost:8000di browser Anda.
Lihat kodenya di examples/modern_dashboard.
🚀 Examples
Kami menyediakan berbagai contoh implementasi untuk membantu Anda memulai:
- Complete Features Demo: Demo semua fitur (CRUD, Operators, Hooks, Encryption) dalam satu file yang rapi.
- SaaS Platform Demo: Implementasi kompleks multi-tenant dengan database terisolasi.
- Hospital Management: Contoh struktur data medis.
- Online Store: Implementasi e-commerce sederhana.
⚙️ Dynamic Configuration
Pengantar Dynamic Configuration
BangronDB mendukung penyimpanan konfigurasi collection secara dinamis dalam database. Konfigurasi seperti ID mode, encryption enabled, schema validation, dan searchable fields dapat disimpan dan dimuat otomatis untuk setiap collection.
Catatan Keamanan: Encryption key TIDAK disimpan di database. Key harus disediakan dari luar (.env, Vault, AWS Secrets, dll). Config hanya menyimpan
encryption_enabled(boolean).
Lihat juga: Configuration Workflow untuk panduan lengkap tentang kapan dan bagaimana menggunakan
saveConfiguration().
Struktur Tabel _config
CREATE TABLE _config ( id INTEGER PRIMARY KEY, document TEXT -- JSON dengan konfigurasi )
Format JSON:
{
"_id": "users",
"id_mode": "auto",
"encryption_enabled": true,
"searchable_fields": {"email": true},
"schema": {...},
"soft_deletes_enabled": true,
"deleted_at_field": "_deleted_at",
"custom_config": {...},
"created_at": "2024-01-01T00:00:00+00:00",
"updated_at": "2024-01-15T10:30:00+00:00"
}
Auto-Load Configuration
Ketika collection diinisialisasi, konfigurasi akan otomatis dimuat dari database:
// Konfigurasi otomatis dimuat dari tabel _config $users = $db->users; // encryption_enabled, schema, searchable fields otomatis diterapkan // Encryption: Key harus disediakan saat runtime! $users->setEncryptionKey($_ENV['DB_ENCRYPTION_KEY']); // WAJIB untuk enkripsi
Mengatur Konfigurasi Dinamis
$users = $db->users; // Set konfigurasi seperti biasa $users->setIdModePrefix('USR'); $users->setSchema([ 'email' => ['required' => true, 'type' => 'string'] ]); $users->setSearchableFields(['email'], true); $users->useSoftDeletes(true); // Encryption: Key dari .env, config hanya simpan boolean $users->setEncryptionKey($_ENV['DB_ENCRYPTION_KEY']); // Simpan konfigurasi ke database (WAJIB untuk persistence) $users->saveConfiguration(); // Di _config: {"_id": "users", "encryption_enabled": true, ...}
PENTING: Encryption key TIDAK disimpan di config. Selalu sediakan key saat runtime dari .env atau secret manager.
Mengelola Konfigurasi Database
// Simpan konfigurasi collection secara manual $db->saveCollectionConfig('users', [ 'id_mode' => 'prefix', 'encryption_enabled' => true, // Boolean saja, bukan key! 'searchable_fields' => ['email' => true, 'phone' => false], 'schema' => [ 'email' => ['required' => true, 'type' => 'string'] ], 'soft_deletes_enabled' => true, 'deleted_at_field' => '_deleted_at', 'custom_config' => [ 'permissions' => [ 'admin' => ['create', 'read', 'update', 'delete'], 'editor' => ['create', 'read', 'update'], 'viewer' => ['read'] ] ] ]); // Load konfigurasi collection $config = $db->loadCollectionConfig('users'); // Load semua konfigurasi collection $allConfigs = $db->getAllCollectionConfigs(); // Hapus konfigurasi collection $db->deleteCollectionConfig('users');
Catatan: Encryption key TIDAK boleh diserialisasi. Selalu sediakan key saat runtime via
setEncryptionKey()atau optionencryption_keysaat membuat Database.
Migrasi Collection dengan Konfigurasi
// Backup konfigurasi sebelum migrasi $oldConfig = $db->loadCollectionConfig('old_users'); // Migrasi data $oldCollection = $db->old_users; $newCollection = $db->users; foreach ($oldCollection->find() as $doc) { $newCollection->insert($doc); } // Terapkan konfigurasi lama ke collection baru $db->saveCollectionConfig('users', $oldConfig);
Best Practices untuk Dynamic Configuration
- Versioning Konfigurasi: Simpan versi konfigurasi untuk rollback
- Backup Konfigurasi: Backup konfigurasi sebelum perubahan besar
- Environment-specific: Gunakan konfigurasi berbeda per environment
- Migration Scripts: Buat script untuk migrasi konfigurasi
class ConfigManager { private Database $db; public function __construct(Database $db) { $this->db = $db; } public function backupCollectionConfig(string $collectionName): array { return $this->db->loadCollectionConfig($collectionName) + [ 'backup_at' => date('c'), 'version' => $this->db->selectCollection($collectionName)->getLastModified()['version'] ]; } public function restoreCollectionConfig(string $collectionName, array $backup): void { unset($backup['backup_at'], $backup['version']); $this->db->saveCollectionConfig($collectionName, $backup); } }
Keamanan Konfigurasi
- Enkripsi Konfigurasi: Pertimbangkan mengenkripsi data konfigurasi sensitif
- Access Control: Kontrol akses ke tabel
_collections - Audit Logging: Log perubahan konfigurasi untuk audit trail
🏢 Enterprise Readiness
Apakah BangronDB layak digunakan di perusahaan?
Ya, BangronDB sangat layak untuk skenario spesifik berikut:
✅ Kapan Menggunakan BangronDB:
- Internal Tools & ERP: Sangat cepat untuk dideploy tanpa perlu setup server database (MongoDB/PostgreSQL) yang rumit.
- Edge Computing / Desktop Apps: Karena berbasis SQLite, database ini "zero-config" dan sangat ringan.
- Microservices Terisolasi: Bagus untuk layanan kecil yang butuh database dokumen pribadi yang cepat.
- Data Sensitif: Dukungan enkripsi AES-256 bawaan membuatnya aman untuk menyimpan data rahasia.
⚠️ Pertimbangan:
- Skala Sangat Besar: Jika data Anda mencapai jutaan record dengan konkurensi tulis yang sangat tinggi, pertimbangkan database server-based (seperti MongoDB asli).
- Horizontal Scaling: BangronDB (SQLite) bersifat file-based, sehingga tidak mendukung replication/sharding native antar server.
Kesimpulan:
BangronDB memberikan keandalan SQLite (ACID Compliant) dengan fleksibilitas NoSQL. Untuk aplikasi tingkat menengah, sistem internal, dan aplikasi desktop, ini adalah pilihan yang sangat solid dan profesional.
BangronDB © 2024 - Document-oriented database untuk PHP dengan enkripsi dan fitur enterprise.
📊 Performa & Benchmark
Berikut adalah hasil pengujian performa BangronDB pada Windows 10 (PHP 8.3, SSD, 1000 records).
Test Environment
- OS: Windows 10/11
- PHP: 8.3.29
- Database Storage: File-based SQLite (.bangron)
- Records: 1000 test documents
Hasil Benchmark Aktual (Feb 13, 2026)
| Operation | Time | Records/Ops | Performance |
|---|---|---|---|
| Insert (single, 1000x) | 215.24 ms | ~4,600 ops/sec | Baseline |
| Find One (no index, 100x) | 56.19 ms | ~1,780 ops/sec | Slow |
| Create Index (email field) | 2.90 ms | - | Very fast |
| Find One (with index, 100x) | 2.85 ms | ~35,000 ops/sec | ⚡ 19.7x faster |
| Update (100x) | 19.68 ms | ~5,000 ops/sec | Good |
| Count (dengan criteria) | 1.41 ms | - | Very fast |
| Pagination (50 pages × 20 items) | 5.08 ms | ~0.10 ms/page | Excellent |
| Searchable Fields (setup + hashing) | 258.52 ms | - | One-time setup |
| Query Encrypted (searchable indexed, 100x) | 15.73 ms | ~6,350 ops/sec | Fast |
Key Performance Insights
-
Indexing Impact: Index creation memberikan 19.7x speedup untuk find operations
- Without index: 56.19 ms untuk 100 queries
- With index: 2.85 ms untuk 100 queries
-
Insert Performance: Single insert cukup cepat untuk aplikasi umum
- ~4,600 ops/sec untuk insert satu per satu
- Bulk insert akan jauh lebih cepat (direkomendasikan)
-
Searchable Fields: Overhead minimal untuk encrypted search
- Setup: 258.52 ms (dilakukan sekali saat konfigurasi)
- Query: ~6,350 ops/sec (cepat dengan index)
-
Pagination: Sangat efficient untuk large datasets
- Skip + Limit operations: ~0.10 ms per page (20 items)
- Optimal untuk meng-handle user uploads/downloads
Performance Tips untuk Production
-
Always Create Indexes untuk fields yang sering di-query
$collection->createIndex('email'); $collection->createIndex('created_at');
-
Use Bulk Operations untuk large datasets
$collection->insert([$doc1, $doc2, $doc3]); // Batch operation
-
Implement Pagination untuk UI responsif
$collection->find()->skip(($page-1)*20)->limit(20)->toArray();
-
Monitor Health secara berkala
$health = $db->getHealthReport();
Benchmark Scripts
- examples/test-benchmark.php - Simple test (recommended)
- examples/22-benchmark.php - Comprehensive (12 tests)
- examples/23-benchmark-searchable.php - Searchable fields focused
Tip
Jalankan dengan: php examples/test-benchmark.php. Hasil akan bervariasi berdasarkan hardware Anda.
🎉 BangronDB siap digunakan untuk proyek Anda! Lihat Enterprise Readiness untuk panduan skalabilitas.