PHPackages                             herdianrony/bangrondb - 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. herdianrony/bangrondb

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

herdianrony/bangrondb
=====================

SQLite-based NoSQL document database with MongoDB-like API, encryption, hooks, relationships, and enterprise features

v1.3.0(1mo ago)0432MITPHPPHP ^8.1CI passing

Since Jun 20Pushed 1mo agoCompare

[ Source](https://github.com/herdianrony/BangronDB)[ Packagist](https://packagist.org/packages/herdianrony/bangrondb)[ Docs](https://github.com/herdianrony/BangronDB)[ RSS](/packages/herdianrony-bangrondb/feed)WikiDiscussions master Synced 1w ago

READMEChangelogDependencies (6)Versions (6)Used By (0)

BangronDB
=========

[](#bangrondb)

Saya bikin BangronDB karena di project-project saya (ERP, CRM, POS, HRIS) saya berulang kali butuh hal yang sama: database dokumen yang fleksibel, bisa di-deploy tanpa setup server, dan punya API yang enak dipakai. MongoDB-style API di atas SQLite adalah jawaban saya.

Library ini cocok untuk aplikasi yang di-deploy per-customer (appliance model), embedded di sistem existing, atau project SMB yang tidak butuh PostgreSQL/MySQL. Bukan untuk SaaS multi-tenant skala besar — gunakan PostgreSQL + RLS untuk itu.

[![License](https://camo.githubusercontent.com/8bb50fd2278f18fc326bf71f6e88ca8f884f72f179d3e555e20ed30157190d0d/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d677265656e2e737667)](LICENSE)[![PHP](https://camo.githubusercontent.com/3a551e6c37f4d5451a70062155ccea8dec2f6eb8a55eb1a1410a5166fce4b020/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f7068702d253345253344253230382e312d626c75652e737667)](https://www.php.net)[![PHPStan](https://camo.githubusercontent.com/2761aeebb3945f1ca4e4b0f156a71a3558c10dd6e3da83b1feb44f4d33013329/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5048505374616e2d6c6576656c253230362d627269676874677265656e2e737667)](phpstan.neon)[![CI](https://github.com/herdianrony/BangronDB/actions/workflows/ci.yml/badge.svg)](https://github.com/herdianrony/BangronDB/actions/workflows/ci.yml)[![Tests](https://camo.githubusercontent.com/a06798a5be55b481314fe151723583703c05212b98659768d775338ff5abf379/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f74657374732d3337362532307061737365642d627269676874677265656e2e737667)](tests)[![Version](https://camo.githubusercontent.com/dc0c8fa1a6c0944f3286719f450dd0dc554f92ec84fa9741531065c27e5e007d/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f76657273696f6e2d312e332e302d626c75652e737667)](https://github.com/herdianrony/BangronDB/releases)[![Packagist](https://camo.githubusercontent.com/fdf726f1737a57cc80c8b0fbc09c27ab4a90c0e0de816399ca05227d787250c5/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f6865726469616e726f6e792f62616e67726f6e64622e737667)](https://packagist.org/packages/herdianrony/bangrondb)

Sorotan Fitur
-------------

[](#sorotan-fitur)

- API mirip MongoDB untuk operasi dokumen
- Backend SQLite berbasis file atau in-memory
- **Dual query strategy**: SQL-first via `json_extract`, fallback ke PHP-side `UtilArrayQuery` untuk query kompleks
- Enkripsi dokumen dengan **AES-256-GCM** + key rotation (v1.2.0)
- Searchable fields (blind index SHA-256) untuk query pada data terenkripsi
- Hooks untuk lifecycle insert, update, dan remove
- Schema validation: type, enum/options, regex, min/max, unique constraint
- Aggregation pipeline: `$match`, `$group`, `$sort`, `$limit`, `$skip`, `$project`, `$count`, `$unset`
- Soft delete dengan restore dan force delete
- TTL (Time-To-Live) auto-expiration
- Cursor streaming via PHP Generator untuk efisiensi memori
- ID mode fleksibel: UUID, manual, prefix
- Populate relasi antar-collection dan antar-database
- `EXPLAIN` query plan dan optimization suggestions
- Health metrics, integrity check, dan change notification
- Konfigurasi collection yang persisten ke database
- Security auditor utilitas (opsional)

Arsitektur
----------

[](#arsitektur)

### Struktur Kode

[](#struktur-kode)

```
src/
├── Client.php              # Entry point: mengelola banyak database
├── Database.php            # Satu file .bangron / :memory:
├── Collection.php          # Tabel dokumen (menggunakan traits)
├── Cursor.php              # Lazy query result iterator
├── QueryExecutor.php       # Eksekusi SQL via PDO prepared statements
├── UtilArrayQuery.php      # PHP-side query engine (fallback)
├── Config.php              # Global configuration
├── Enums/                  # Enum: HookEvent, IdMode
├── Exceptions/             # Typed exceptions
├── Security/               # SecurityAuditor (utilitas opsional)
└── Traits/                 # Fitur-fitur collection (horizontal reuse)
    ├── QueryBuilderTrait.php
    ├── EncryptionTrait.php
    ├── SchemaValidationTrait.php
    ├── HooksTrait.php
    ├── SearchableFieldsTrait.php
    ├── IdGeneratorTrait.php
    ├── SoftDeleteTrait.php
    ├── TtlTrait.php
    ├── ChangeTrackingTrait.php
    └── ConfigurationPersistenceTrait.php

```

### Desain Trait-based

[](#desain-trait-based)

`Collection` menggunakan **traits** untuk horizontal code reuse — bukan inheritance. Setiap trait adalah unit tunggal yang fokus pada satu tanggung jawab:

TraitTanggung Jawab`QueryBuilderTrait`Query logic, `find()`, `findOne()`, `count()`, operator parsing`EncryptionTrait`Enkripsi/dekripsi AES-256-GCM, key rotation`SchemaValidationTrait`Validasi type, enum, regex, min/max, unique`HooksTrait`Event lifecycle (before/after insert/update/remove)`SearchableFieldsTrait`Blind index untuk query pada data terenkripsi`IdGeneratorTrait`UUID, manual, prefix ID generation`SoftDeleteTrait`Soft delete, restore, force delete`TtlTrait`Auto-expiration dokumen berdasarkan TTL`ChangeTrackingTrait`Versioning dan change notification`ConfigurationPersistenceTrait`Simpan/muat konfigurasi collection ke databasePendekatan ini menjaga `Collection.php` tetap ringan sebagai koordinator, sementara logika detail tersebar di file terpisah yang bisa di-maintain secara independen.

### Dual Query Strategy

[](#dual-query-strategy)

BangronDB menggunakan **dua lapis query** secara otomatis:

```
Query masuk → _canTranslateToJsonWhere()?
                ├─ YA → _buildJsonWhere() → SQL WHERE via json_extract/->>/->  (cepat)
                └─ TIDAK → fetch semua → UtilArrayQuery::match() di PHP        (fleksibel)

```

- **SQL-first**: Query sederhana (equality, comparison, `$in`, logical operators) diterjemahkan ke SQL `WHERE json_extract(document, '$.field')` dan dieksekusi langsung oleh SQLite engine. Ini memanfaatkan index dan meminimalkan data yang di-load ke PHP.
- **PHP fallback**: Query kompleks (regex, closure/`$where`, fuzzy search, dot notation nested) yang tidak bisa diterjemahkan ke SQL menggunakan `UtilArrayQuery` untuk filtering di level PHP.

Strategi ini otomatis — pengguna tidak perlu memilih secara manual.

### Yang BUKAN Bagian Core

[](#yang-bukan-bagian-core)

Beberapa fitur yang sering dikira built-in sebenarnya adalah **pola aplikasi** yang didemonstrasikan di `examples/`, bukan bagian dari library:

- **RBAC/ACL** → Contoh 22, 23, 24: pola menggunakan `setCustomConfig()` + hooks untuk enforce permission di application layer
- **Change tracking audit log** → Contoh di examples: pola menggunakan hooks untuk mencatat perubahan
- **Authentication** → Contoh 20: pola hashing password + hooks

BangronDB menyediakan **primitif** (hooks, schema, custom config) yang memungkinkan pola-pola ini dibangun di atasnya, tanpa memaksakan paradigma tertentu ke aplikasi pengguna.

Kebutuhan Sistem
----------------

[](#kebutuhan-sistem)

- PHP **8.1+**
- Ekstensi `pdo_sqlite`
- Ekstensi `openssl`
- Composer

Instalasi
---------

[](#instalasi)

```
composer require herdianrony/bangrondb
```

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

[](#quick-start)

```
use BangronDB\Client;

$client = new Client(__DIR__ . '/data');
$client->createDB('app');
$client->createCollection('app', 'users');

$users = $client->selectCollection('app', 'users');

// Insert
$userId = $users->insert([
    'name' => 'John Doe',
    'email' => 'john@example.com',
    'role' => 'admin',
]);

// Find
$user = $users->findOne(['_id' => $userId]);

echo $user['name'] . PHP_EOL;

// Update
$users->update(['_id' => $userId], [
    '$set' => ['role' => 'superadmin'],
]);

// Delete
$users->remove(['_id' => $userId]);
```

Konsep Dasar
------------

[](#konsep-dasar)

```
Client -> Database (.bangron / :memory:) -> Collection -> Document

```

- **Client** mengelola banyak database dalam satu path.
- **Database** mewakili satu file SQLite/BangronDB.
- **Collection** mewakili tabel dokumen.
- **Document** disimpan sebagai JSON.

Membuat Client dan Database
---------------------------

[](#membuat-client-dan-database)

```
use BangronDB\Client;

// File-based storage
$client = new Client(__DIR__ . '/data');

// In-memory
$memoryClient = new Client(':memory:');

// Dengan opsi runtime
$secureClient = new Client(__DIR__ . '/data', [
    'encryption_key' => $_ENV['DB_ENCRYPTION_KEY'] ?? null,
    'query_logging' => false,
    'performance_monitoring' => false,
]);

// API eksplisit untuk lifecycle database
$client->createDB('app');
$client->dbExists('app'); // true

$db = $client->selectDB('app');
$db = $client->app; // magic getter, untuk database yang sudah ada

$client->createCollection('app', 'users');
$client->collectionExists('app', 'users'); // true
$client->listCollections('app');           // ['users', ...] (alias: listCollection)

$users = $client->selectCollection('app', 'users');
$users = $db->users; // magic getter, untuk collection yang sudah ada

$client->renameCollection('app', 'users', 'members');
$client->dropCollection('app', 'members');

// Atau dari object Database jika lebih nyaman
$db->createCollection('logs');
$db->collectionExists('logs'); // true

// Rename / hapus database
$client->renameDB('app', 'app_v2');
$client->dropDB('app_v2');

$client->close();
```

> Mulai versi ini, `selectDB()` dan `selectCollection()` bersifat **non-lazy**: keduanya hanya memilih resource yang sudah ada.
>
> Untuk membuat resource baru secara eksplisit, gunakan:
>
> - `createDB()` untuk database
> - `createCollection()` untuk collection

CRUD
----

[](#crud)

### Insert

[](#insert)

```
$id = $users->insert([
    'name' => 'Alice',
    'email' => 'alice@example.com',
]);

$count = $users->insert([
    ['name' => 'Bob'],
    ['name' => 'Charlie'],
]);
```

### InsertMany / UpdateMany / DeleteMany (API MongoDB-compatible)

[](#insertmany--updatemany--deletemany-api-mongodb-compatible)

```
// InsertMany: insert batch dengan hasil detail
$result = $users->insertMany([
    ['name' => 'Alice', 'email' => 'alice@example.com'],
    ['name' => 'Bob',   'email' => 'bob@example.com'],
]);
// ['inserted_count' => 2, 'inserted_ids' => ['...', '...']]

// UpdateMany: update semua dokumen yang cocok
$result = $users->updateMany(['status' => 'pending'], ['$set' => ['status' => 'active']]);
// ['matched_count' => 5, 'modified_count' => 5]

// DeleteMany
$result = $users->deleteMany(['status' => 'banned']);
// ['deleted_count' => 2]
```

### Find

[](#find)

```
$all = $users->find()->toArray();
$one = $users->findOne(['name' => 'Alice']);

$activeAdults = $users->find([
    'status' => 'active',
    'age' => ['$gte' => 21],
])->toArray();

$projection = $users->find(
    ['status' => 'active'],
    ['name' => 1, 'email' => 1]
)->toArray();

$total = $users->count(['status' => 'active']);
```

### Update

[](#update)

```
// Merge update (default)
$users->update(['name' => 'Alice'], ['city' => 'Jakarta']);

// Replace update
$users->update(['name' => 'Alice'], ['name' => 'Alice', 'city' => 'Bandung'], false);

// Operator-style update
$users->update(['name' => 'Alice'], [
    '$set' => ['role' => 'editor'],
    '$unset' => ['legacy_field' => ''],
]);
```

### Save / Upsert

[](#save--upsert)

```
// Tanpa _id => insert baru
$newId = $users->save(['name' => 'Dina']);

// Dengan _id => update jika sudah ada, insert jika belum ada
$users->save([
    '_id' => 'USR-000001',
    'name' => 'Dina Updated',
]);
```

### Delete

[](#delete)

```
$deleted = $users->remove(['status' => 'inactive']);
$users->remove([]); // hapus semua dokumen
```

Pagination, Sorting, Projection
-------------------------------

[](#pagination-sorting-projection)

```
$results = $users->find(['status' => 'active'])
    ->sort(['age' => 1])
    ->skip(10)
    ->limit(5)
    ->toArray();
```

Query Operators
---------------

[](#query-operators)

### Comparison

[](#comparison)

```
$users->find(['age' => ['$gt' => 18]]);
$users->find(['age' => ['$gte' => 21]]);
$users->find(['age' => ['$lt' => 65]]);
$users->find(['age' => ['$lte' => 60]]);
$users->find(['age' => ['$ne' => 30]]);
```

### Array / Membership

[](#array--membership)

```
$users->find(['role' => ['$in' => ['admin', 'editor']]]);
$users->find(['role' => ['$nin' => ['guest', 'banned']]]);
$users->find(['tags' => ['$all' => ['php', 'sqlite']]]);
$users->find(['tags' => ['$size' => 3]]);
```

### Existence dan Logical

[](#existence-dan-logical)

```
$users->find(['email' => ['$exists' => true]]);

$users->find(['$or' => [
    ['age' => ['$lt' => 18]],
    ['age' => ['$gt' => 65]],
]]);

$users->find(['$and' => [
    ['status' => 'active'],
    ['age' => ['$gte' => 21]],
]]);
```

### Regex, Closure, Fuzzy Search, Dot Notation

[](#regex-closure-fuzzy-search-dot-notation)

```
$users->find(['name' => ['$regex' => '^John']]);

$users->find(['age' => ['$where' => fn($doc) => $doc['age'] > 18]]);
$users->find(['name' => ['$func' => fn($val) => strlen($val) > 5]]);

$users->find([
    'description' => [
        '$fuzzy' => [
            '$search' => 'important',
            '$minScore' => 0.7,
        ],
    ],
]);

$users->find(['address.city' => 'Jakarta']);
```

> `'$where'` dan `'$func'` hanya menerima **Closure**, bukan string function name.

Aggregation Pipeline
--------------------

[](#aggregation-pipeline)

```
$results = $users->aggregate([
    ['$match'  => ['status' => 'active']],
    ['$group'  => ['_id' => '$role', 'total' => ['$sum' => 1], 'avg_age' => ['$avg' => '$age']]],
    ['$sort'   => ['total' => -1]],
    ['$limit'  => 10],
]);
```

Operator yang didukung:

StageDeskripsi`$match`Filter dokumen (sintaks sama seperti `find()`)`$group`Grouping dengan akumulator: `$sum`, `$avg`, `$min`, `$max`, `$count`, `$first`, `$last`, `$push`, `$addToSet``$sort`Urutkan dokumen`$limit`Batasi jumlah hasil`$skip`Lewati N dokumen pertama`$project`Reshape dokumen (include/exclude field, field reference)`$count`Hitung dokumen yang lolos pipeline`$unset`Hapus field dari semua dokumenField reference menggunakan prefix `$`: `'$fieldName'` merujuk ke nilai field dokumen.

Cursor Streaming
----------------

[](#cursor-streaming)

Untuk dataset besar, gunakan `stream()` yang menghasilkan `Generator` — memori tetap konstan terlepas dari ukuran hasil:

```
foreach ($users->stream(['status' => 'active'], [
    'sort'  => ['created_at' => -1],
    'limit' => 10000,
]) as $doc) {
    processDocument($doc); // hanya satu dokumen di memori
}
```

Explain Query
-------------

[](#explain-query)

Analisis bagaimana query dieksekusi — apakah menggunakan index, full scan, dan saran optimasi:

```
$explanation = $users->explain(['status' => 'active', 'age' => ['$gte' => 21]]);

echo $explanation['query_plan']['uses_index'] ? 'Uses index' : 'Full scan';
echo "Scanned: {$explanation['performance']['documents_scanned']} documents";
echo "Time: {$explanation['performance']['execution_time_ms']}ms";

foreach ($explanation['suggestions'] as $suggestion) {
    echo "Suggestion: {$suggestion}";
}
```

Enkripsi
--------

[](#enkripsi)

### Database-level encryption

[](#database-level-encryption)

```
use BangronDB\Database;

$db = new Database(__DIR__ . '/secure.bangron', [
    'encryption_key' => $_ENV['DB_ENCRYPTION_KEY'],
]);
```

### Collection-level encryption

[](#collection-level-encryption)

```
$users->setEncryptionKey($_ENV['DB_ENCRYPTION_KEY']);

$users->insert([
    'name' => 'Alice',
    'ssn' => '123-45-6789',
]);
```

### Searchable fields untuk data terenkripsi

[](#searchable-fields-untuk-data-terenkripsi)

```
$users->setEncryptionKey($_ENV['DB_ENCRYPTION_KEY']);

// Format baru (direkomendasikan) — kontrol per-field
$users->setSearchableFields([
    'email' => ['hash' => true],     // HMAC-SHA256 blind index (aman)
    'username' => ['hash' => false], // Plain text (untuk field non-sensitif)
]);

// Format lama (masih didukung) — semua field mendapat perlakuan sama
$users->setSearchableFields(['email', 'phone'], true);

$users->saveConfiguration();
```

**Catatan teknis:** BangronDB menggunakan **AES-256-GCM**, key derivation berbasis PBKDF2 SHA-256, IV acak per enkripsi, dan payload Base64 di dokumen JSON. Key version (v1.2.0) memungkinkan key rotation tanpa re-encrypt manual.

### Key Rotation

[](#key-rotation)

```
// Set key lama, lalu rotate ke key baru
$users->setEncryptionKey($oldKey, 'v1');
$rotated = $users->rotateEncryptionKey($newKey, 'v2'); // return jumlah dokumen

// Set key baru sebagai active
$users->setEncryptionKey($newKey, 'v2');
```

> Lihat contoh 21 (`21-key-rotation.php`) untuk demo lengkap termasuk `reencryptAll()`.

Schema Validation
-----------------

[](#schema-validation)

```
$users->setSchema([
    'username' => ['required' => true, 'type' => 'string', 'min' => 3, 'max' => 50],
    'email'    => ['required' => true, 'type' => 'string', 'unique' => true, 'regex' => '/^[^\s@]+@[^\s@]+\.[^\s@]+$/'],
    'age'      => ['type' => 'int', 'min' => 13, 'max' => 120],
    'role'     => ['type' => 'string', 'enum' => ['admin', 'user', 'moderator']],
]);

$users->validate([
    'username' => 'john',
    'email' => 'john@example.com',
]);
```

> Validasi `enum` menggunakan strict comparison. Misalnya, nilai `0`, `false`, dan `'0'` dianggap berbeda.

### Unique constraint

[](#unique-constraint)

Tandai sebuah field dengan `'unique' => true` agar BangronDB menolak dokumen baru (atau update) yang nilainya sudah ada di koleksi. Pengecekan dijalankan otomatis saat `insert()` / `update()` dan melempar `ValidationException`(`UNIQUE_CONSTRAINT_VIOLATION`). Nilai `null` tidak dikenai constraint, dan update pada dokumen yang sama (nilai tidak berubah) tidak dianggap duplikat.

```
$users->setSchema(['email' => ['type' => 'string', 'unique' => true]]);
$users->insert(['email' => 'a@example.com']);
$users->insert(['email' => 'a@example.com']); // throws ValidationException
```

> Catatan untuk field **terenkripsi**: pengecekan unik memakai query equality, sehingga pada koleksi terenkripsi field tersebut harus juga dijadikan **searchable** (`setSearchableFields([... => ['hash' => true]])`) agar nilai dapat dicari lewat blind index. Tanpa itu, dokumen terenkripsi tidak bisa di-query per-nilai dan constraint tidak akan menemukan duplikat.

> Lihat [docs/schema-metadata-guide.md](docs/schema-metadata-guide.md) untuk panduan lengkap tentang properti metadata (`label`, `ui`, `relation`, dll.) yang tidak divalidasi otomatis.

TTL (Time-To-Live)
------------------

[](#ttl-time-to-live)

Dokumen bisa di-set untuk auto-expire setelah waktu tertentu:

```
// Aktifkan TTL pada field 'expires_at' dengan default 1 jam
$logs->enableTtl('expires_at', 3600);

// Tanpa default TTL (set manual per dokumen)
$logs->enableTtl('expires_at');

$logs->insert(['message' => 'temp log']); // otomatis dapat expires_at = now() + 3600

// Insert dengan expiry manual (override default)
$logs->insert(['message' => 'short', 'expires_at' => time() + 300]);

// Bersihkan dokumen yang sudah expired
$removed = $logs->cleanExpired();

// Statistik TTL
$stats = $logs->ttlStats();
```

> `cleanExpired()` harus dipanggil manual (misalnya via cron). BangronDB tidak membersihkan otomatis.

Soft Deletes
------------

[](#soft-deletes)

```
$users->useSoftDeletes(true);

$users->remove(['username' => 'johndoe']);
$users->find()->withTrashed()->toArray();
$users->find()->onlyTrashed()->toArray();
$users->restore(['username' => 'johndoe']);
$users->forceDelete(['username' => 'johndoe']);
```

Hooks
-----

[](#hooks)

```
$users->on('beforeInsert', function ($document) {
    $document['created_at'] = date('c');
    return $document;
});

$users->on('afterInsert', function ($document, $insertId) {
    error_log('Inserted: ' . $insertId);
});

$users->on('beforeUpdate', function ($criteria, $data) {
    $data['updated_at'] = date('c');
    return ['criteria' => $criteria, 'data' => $data];
});

$users->on('beforeRemove', function ($document) {
    if ($document['protected'] ?? false) {
        return false; // reject deletion
    }
});
```

Event yang tersedia:

- `beforeInsert` / `afterInsert`
- `beforeUpdate` / `afterUpdate`
- `beforeRemove` / `afterRemove`

> Hook adalah **primitif** yang fleksibel. Bisa digunakan untuk ACL enforcement, audit logging, auto-timestamp, data transformation, dan lain-lain — semuanya di application layer, bukan di core library.

Relationships / Populate
------------------------

[](#relationships--populate)

```
$posts = $db->posts->find()
    ->populate('author_id', $db->users, ['as' => 'author'])
    ->toArray();

$post = $db->posts->populate($post, 'comment_ids', 'app.comments', '_id', 'comments');
```

Indexing
--------

[](#indexing)

```
$users->createIndex('email');
$users->createIndex('address.city');
$users->createIndex('status', 'idx_status');

$db->dropIndex('idx_status');
```

Health &amp; Monitoring
-----------------------

[](#health--monitoring)

```
$health = $db->getHealthMetrics();
$report = $db->getHealthReport();
$perf   = $db->getPerformanceMetrics();
$index  = $db->getIndexMetrics();
$coll   = $db->getCollectionMetrics();

$db->checkIntegrity();
$db->vacuum();
```

Change Notification
-------------------

[](#change-notification)

```
$lastModified = $users->getLastModified();
// ['version' => 42, 'last_updated' => '2026-06-20T10:30:45+07:00']

$users->notifyChange();
```

Dynamic Configuration
---------------------

[](#dynamic-configuration)

Konfigurasi collection berikut bisa disimpan ke database:

- ID mode
- searchable fields
- schema
- soft deletes
- custom config

```
$users->setIdModePrefix('USR');
$users->setSearchableFields(['email'], true);
$users->setSchema([...]);
$users->useSoftDeletes(true);
$users->saveConfiguration();
```

### Custom Config

[](#custom-config)

Simpan metadata aplikasi per collection — persisten dan auto-load saat reconnect:

```
// Simpan ACL, settings, atau metadata lain
$users->setCustomConfig('acl', [
    'admin'  => ['create', 'read', 'update', 'delete'],
    'editor' => ['create', 'read', 'update'],
    'viewer' => ['read'],
]);
$users->setCustomConfig('max_login_attempts', 3);
$users->saveConfiguration();

// Baca kapan saja
$acl = $users->getCustomConfig('acl');
$all = $users->getAllCustomConfig();
```

> Sensitive keys (`encryption_key`, `password`, `secret`, `token`, dll.) **ditolak** otomatis dan tidak bisa disimpan via `setCustomConfig`. Encryption key selalu supply dari `.env`, secret manager, atau runtime config.
>
> Catatan: konfigurasi ID prefix yang dipersist kini dinormalisasi ke format `prefix:USR`. Konfigurasi lama yang masih menyimpan prefix mentah seperti `USR` tetap didukung saat dibaca ulang.

Transactions
------------

[](#transactions)

BangronDB menggunakan PDO SQLite di bawahnya, jadi Anda bisa memakai transaksi langsung lewat koneksi PDO:

```
$db->connection->beginTransaction();

try {
    $db->users->insert(['name' => 'Alice']);
    $db->profiles->insert(['user' => 'Alice']);
    $db->connection->commit();
} catch (\Throwable $e) {
    $db->connection->rollBack();
    throw $e;
}
```

Keamanan
--------

[](#keamanan)

BangronDB menerapkan beberapa guardrail penting:

FiturTujuanClosure-only untuk `$where` / `$func`Mencegah RCEValidasi field nameMencegah injectionPRAGMA key escapingMencegah SQLite injectionRegex hardening (ReDoS)Mengurangi risiko catastrophic backtrackingValidasi pathMengurangi risiko path traversalSensitive config key blockingMencegah credential leakage`strict_types=1`Type safetyLihat juga [SECURITY\_USAGE\_GUIDE.md](SECURITY_USAGE_GUIDE.md).

API Ringkas
-----------

[](#api-ringkas)

### Client

[](#client)

MethodKeterangan`new Client($path, $options = [])`Membuat client`createDB($name, $options = [])`Membuat database secara eksplisit`dbExists($name)`Mengecek apakah database ada`listDBs()`Daftar database`selectDB($name)`Ambil database`renameDB($oldName, $newName)`Rename database`dropDB($name)`Hapus database`createCollection($db, $collection)`Membuat collection langsung dari level client`collectionExists($db, $collection)`Mengecek collection dari level client`listCollections($db)` / `listCollection($db)`Daftar nama collection di sebuah database (`[]` jika DB tidak ada)`renameCollection($db, $oldName, $newName)`Rename collection dari level client`dropCollection($db, $collection)`Hapus collection dari level client`selectCollection($db, $collection)`Ambil collection langsung`close()`Tutup koneksi### Database

[](#database)

MethodKeterangan`selectCollection($name)`Ambil collection`createCollection($name)`Buat collection`collectionExists($name)`Mengecek apakah collection ada`renameCollection($oldName, $newName)`Rename collection`dropCollection($name)`Hapus collection`getCollectionNames()`Daftar nama collection`createJsonIndex($collection, $field, $indexName = null)`Buat index JSON`dropIndex($indexName)`Hapus index`getHealthMetrics()`Ambil health metrics`getHealthReport()`Ambil health report`getPerformanceMetrics()`Ambil metrik performa`getCollectionMetrics()`Ambil metrik per collection`saveCollectionConfig($name, $config)`Simpan konfigurasi`loadCollectionConfig($name)`Muat konfigurasi`deleteCollectionConfig($name)`Hapus konfigurasi`checkIntegrity()`Jalankan integrity check`vacuum()`Optimasi file database### Collection

[](#collection)

MethodKeterangan`insert($document)`Insert satu/banyak dokumen`insertMany($documents)`Insert batch dengan hasil detail`updateMany($criteria, $data, $options = [])`Update batch dengan hasil detail`deleteMany($criteria)`Delete batch dengan hasil detail`find($criteria = null, $projection = null)`Query dokumen`findOne($criteria = null, $projection = null)`Query satu dokumen`update($criteria, $data, $merge = true)`Update dokumen`remove($criteria)`Hapus dokumen`count($criteria = null)`Hitung dokumen`save($document)`Insert / upsert dokumen`aggregate($pipeline)`Aggregation pipeline`explain($criteria = null)`Query plan analysis`stream($criteria = null, $options = [])`Cursor streaming (Generator)`drop()`Hapus collection`renameCollection($newName)`Rename collection`setIdModeAuto()` / `setIdModeManual()` / `setIdModePrefix($prefix)`Atur mode ID`setEncryptionKey($key, $version = null)`Atur key enkripsi + versi`rotateEncryptionKey($newKey, $newVersion = null)`Rotasi key enkripsi`reencryptAll()`Re-encrypt semua dokumen (bump versi)`setSearchableFields($fields, $hash = false)`Atur searchable fields`removeSearchableField($field, $dropColumn = false)`Hapus searchable field`rehashSearchableField($field)`Rehash blind index (migration)`setSchema($schema)`Atur schema`validate($document)`Validasi dokumen manual`enableTtl($field, $seconds = null)`Aktifkan TTL auto-expiration`disableTtl()`Nonaktifkan TTL`cleanExpired()`Hapus dokumen expired`expiredCount()`Hitung dokumen expired`ttlStats()`Status TTL collection`useSoftDeletes($enabled = true)`Aktifkan soft delete`setDeletedAtField($field)`Custom field name (default: deleted\_at)`restore($criteria)`Restore dokumen terhapus`forceDelete($criteria)`Hapus permanen`on($event, $callback)`Register hook`off($event, $callback = null)`Hapus hook`createIndex($field, $indexName = null)`Buat index`getLastModified()`Ambil metadata perubahan`notifyChange()`Trigger manual change notification`saveConfiguration()`Simpan konfigurasi collection`setCustomConfig($key, $value)`Simpan custom config`getCustomConfig($key, $default = null)`Baca custom config`getAllCustomConfig()`Baca semua custom config### Cursor

[](#cursor)

MethodKeterangan`limit($n)`Batas hasil`skip($n)`Lewati hasil awal`sort($fields)`Urutkan hasil`populate($field, $collection, $options = [])`Populate relasi`withTrashed()`Sertakan soft-deleted`onlyTrashed()`Hanya soft-deleted`toArray()`Materialisasi ke array`toArraySafe($maxResults = null)`Materialisasi dengan batas aman`each($callback)`Iterasi tiap dokumenKonfigurasi Environment
-----------------------

[](#konfigurasi-environment)

Salin `.env.example` menjadi `.env` lalu isi sesuai kebutuhan:

```
DB_PATH=                         # Kosongkan untuk in-memory
ENCRYPTION_KEY=                  # Key kuat minimal 32 karakter
QUERY_LOGGING=false
PERFORMANCE_MONITORING=false
```

Contoh Lengkap
--------------

[](#contoh-lengkap)

Lihat folder [examples/](examples/) untuk contoh end-to-end:

NoFileTopik01`01-quick-start-crud.php`Quick start CRUD02`02-query-operators.php`Query operators03`03-encryption-searchable.php`Enkripsi &amp; searchable fields04`04-schema-validation.php`Schema validation05`05-bulk-operations.php`Bulk insert/update/delete06`06-aggregation-pipeline.php`Aggregation pipeline07`07-cursor-streaming.php`Cursor streaming (Generator)08`08-ttl-expiration.php`TTL auto-expiration09`09-explain-query.php`Explain query plan10`10-soft-deletes.php`Soft delete &amp; restore11`11-hooks.php`Hooks lifecycle12`12-relationships-populate.php`Relasi &amp; populate13`13-transactions.php`Transaksi14`14-indexing-health-monitoring.php`Indexing &amp; health monitoring15`15-dynamic-configuration.php`Konfigurasi dinamis16`16-multiple-databases.php`Multiple databases17`17-id-modes-collection-management.php`ID modes &amp; collection management18`18-security-features.php`Fitur keamanan19`19-ecommerce-app.php`Aplikasi e-commerce lengkap20`20-auth-encrypted.php`Auth dengan enkripsi21`21-key-rotation.php`Key rotation22`22-rbac-users-roles-permissions.php`RBAC (pola aplikasi)23`23-acl-relation-type.php`ACL dengan relation type24`24-dynamic-acl-per-collection.php`Dynamic ACL per collectionDokumentasi
-----------

[](#dokumentasi)

DokumenDeskripsi[Getting Started](docs/getting-started.md)Panduan cepat instalasi dan penggunaan dasar[Fitur Lanjutan](docs/features.md)Hooks, soft delete, TTL, enkripsi, aggregation, dan lainnya[Query Operators](docs/query-operators.md)Daftar lengkap operator query yang didukung[Schema &amp; Metadata Guide](docs/schema-metadata-guide.md)Panduan properti schema, validasi aktif, dan metadata[Hook Patterns](docs/hook-patterns.md)8 pola penggunaan hook dalam aplikasi nyata[Framework Integration](docs/framework-integration.md)Integrasi dengan Laravel, Lumen, Slim, Flight, CodeIgniter 4, Symfony, dan lainnya[API Reference](docs/api-reference.md)Referensi API lengkap[Security](docs/security.md)Keamanan, enkripsi, dan best practices[Roadmap](docs/roadmap.md)Fitur yang sudah dan akan diimplementasikanCatatan Kompatibilitas
----------------------

[](#catatan-kompatibilitas)

Jika Anda bermigrasi dari perilaku lama yang mengandalkan create implicit saat `selectDB()` / `selectCollection()`, lihat:

- [BACKWARD\_COMPATIBILITY\_NOTES.md](BACKWARD_COMPATIBILITY_NOTES.md)

Kontribusi
----------

[](#kontribusi)

Lihat [CONTRIBUTING.md](CONTRIBUTING.md).

Lisensi
-------

[](#lisensi)

BangronDB dilisensikan dengan [MIT](LICENSE).

###  Health Score

42

—

FairBetter than 88% of packages

Maintenance92

Actively maintained with recent releases

Popularity15

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity46

Maturing project, gaining track record

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

Total

5

Last Release

38d ago

PHP version history (2 changes)v1.0.1PHP &gt;=8.0

v1.0.0PHP ^8.1

### Community

Maintainers

![](https://www.gravatar.com/avatar/39bc178d58ce72cadd3a4d1d51f20f9faf82ef707541ff054a39dad7e4b2302c?d=identicon)[herdianrony](/maintainers/herdianrony)

---

Top Contributors

[![herdianrony](https://avatars.githubusercontent.com/u/31861521?v=4)](https://github.com/herdianrony "herdianrony (128 commits)")

---

Tags

jsonencryptiondatabasesqlitenosqlmongodbphp8php-databaseembedded-databasedocument-databaselightweight-database

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Type Coverage Yes

### Embed Badge

![Health badge](/badges/herdianrony-bangrondb/health.svg)

```
[![Health](https://phpackages.com/badges/herdianrony-bangrondb/health.svg)](https://phpackages.com/packages/herdianrony-bangrondb)
```

###  Alternatives

[scienta/doctrine-json-functions

A set of extensions to Doctrine that add support for json query functions.

58926.6M60](/packages/scienta-doctrine-json-functions)[apix/cache

A thin PSR-6 cache wrapper with a generic interface to various caching backends emphasising cache taggging and indexing to Redis, Memcached, PDO/SQL, APC and other adapters.

114550.1k6](/packages/apix-cache)[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.

856.1k](/packages/tommyknocker-pdo-database-class)[moharrum/laravel-adminer

Adminer database management tool for your Laravel application.

451.0k](/packages/moharrum-laravel-adminer)

PHPackages © 2026

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