ifabula / sevola-interceptor-helper
Laravel database interceptor for automatic field encryption/decryption using Sevola SDK
Installs: 2
Dependents: 0
Suggesters: 0
Security: 0
Stars: 0
Forks: 0
pkg:composer/ifabula/sevola-interceptor-helper
Requires
- php: ^8.2
- ifabula/sevola-sdk-php: *
- illuminate/database: ^11.0|^12.0
- illuminate/support: ^11.0|^12.0
Requires (Dev)
- orchestra/testbench: ^9.0
- phpunit/phpunit: ^10.0
This package is not auto-updated.
Last update: 2025-12-24 09:07:53 UTC
README
Zero-integration encryption/decryption for Laravel applications powered by the Sevola SDK.
Configure once in Sevola CMS, install this package, and every Eloquent model automatically honours the encryption rules—no traits, no code changes.
Table of Contents
- Why the Helper Exists
- Key Features
- Requirements
- Installation
- Configuring the Helper
- Quick Start Checklist
- How the Helper Works
- Available Services
- Usage Examples
- Configuration Data Model
- Advanced Topics
- Troubleshooting
- FAQ
- Contributing & Support
Why the Helper Exists
Enterprises often need to encrypt Personally Identifiable Information (PII) without rewriting existing Laravel codebases. The Sevola PHP Interceptor Helper reads field-level encryption rules from Sevola CMS, transparently encrypts data before it is written, and decrypts it again when read—so developers keep using Eloquent exactly as before.
Key Features
- 🔐 True zero-integration – encryption happens automatically for every Eloquent model and query builder call; no traits or manual hooks.
- 🧠 Configuration-driven – encryption rules live in Sevola CMS (
mst_encryption_configtable), not in source code. - ⚡ Global interception – the service provider attaches framework-level listeners to
savingandretrievedevents. - 🎯 Column-level control – pick exactly which columns are encrypted, per-table, per-database.
- 🧮 Algorithm aware – supports FF1 format-preserving encryption, AES-REST, transit keys, etc. (whichever the CMS configuration specifies).
- 🗄️ Cache friendly – configuration is cached (TTL configurable) to minimise database lookups.
- 🪵 Rich logging – optional structured logging for auditing and debugging.
- 🛠️ Manual APIs still available – access
ConfigService,EncryptionService, andModelEncryptionManagerfor one-off jobs or raw queries. - 🎚️ Per-request ciphertext toggle – opt in to encrypted responses using
SevolaContext.
Requirements
| Component | Minimum |
|---|---|
| PHP | 8.2 |
| Laravel | 11.x (works with L10 via manual provider registration) |
| Database | Any connection supported by Laravel (MySQL, PostgreSQL, SQL Server, etc.) |
| Sevola SDK | ifabula/sevola-sdk-php (installed automatically) |
Installation
Require the package
composer require ifabula/sevola-interceptor-helper(Optional) Publish the configuration file
php artisan vendor:publish --tag=sevola-configThis creates
config/sevola.php. Publishing is recommended when you need to customise defaults (cache TTL, log channel, etc.).Ensure the Sevola SDK is available
The helper already depends onifabula/sevola-sdk-php, so the SDK will be installed automatically.Laravel service provider
- Laravel 11+: auto-discovery registers the provider.
- Laravel ≤ 10: add
Ifabula\SevolaInterceptor\SevolaServiceProvider::classto theprovidersarray inconfig/app.php.
Configuring the Helper
1. Environment variables
Add these entries to .env (or use your secrets manager):
# Required
SEVOLA_API_KEY=your-api-key
SEVOLA_BASE_URL=https://sevola.example.com
SEVOLA_CONFIG_DATABASE=amplio_encrypt_dev
SEVOLA_CONFIG_TABLE=mst_encryption_config
# Optional
SEVOLA_DB_CONNECTION=null # Defaults to Laravel's default DB connection
SEVOLA_CACHE_TTL=300 # Seconds
SEVOLA_LOGGING=false # Enable structured logs
SEVOLA_LOG_CHANNEL=stack # Use any Laravel channel name
SEVOLA_DEBUG=false # Adds verbose debug logs
SEVOLA_ENABLE_QUERY_LISTENER=false # Experimental raw-query interceptor (disabled by default)
The helper uses the configured connection (or the default connection) to query the CMS configuration table.
2. Sevola CMS configuration
Encryption rules are managed centrally in Sevola CMS. For each table you want to protect:
- Open Encryption Config inside Sevola CMS.
- Create an entry specifying database, table, columns to encrypt, and the algorithm.
- Set the entry status to ACTIVE.
The helper reads this table (mst_encryption_config) on demand. Once the config is active, every Laravel query that touches that table automatically encrypts/decrypts the listed columns.
No code changes are needed in the Laravel project. As soon as the config exists and the helper is installed, the model data is protected.
Quick Start Checklist
- ✅ Install the package (
composer require ifabula/sevola-interceptor-helper). - ✅ Configure
.envwith Sevola API and CMS database credentials. - ✅ Ensure the Sevola CMS entry exists for each table (status = ACTIVE).
- ✅ (Laravel ≤ 10) Register the service provider manually.
- ▶️ Use your Eloquent models and query builder exactly as before—encrypted columns are handled automatically.
To verify quickly, enable logging (SEVOLA_LOGGING=true, SEVOLA_DEBUG=true) and inspect storage/logs/laravel.log. You should see messages confirming encryption/decryption activity for configured tables.
How the Helper Works
- Bootstrapping –
SevolaServiceProvidermerges configuration, registers services, and attaches listeners to global Eloquent events. - On Save – When a model is saved (create/update),
Model::savingfires. The helper:- resolves the model’s connection/database/table;
- queries the CMS configuration (cached);
- encrypts only the columns listed as encrypted; and
- writes the encrypted values back onto the model before the INSERT/UPDATE happens.
- resolves the model’s connection/database/table;
- On Retrieve – When a model is retrieved,
Model::retrievedfires. The helper:- fetches the same configuration;
- decrypts the relevant attributes on the model instance; and
- calls
syncOriginal()so Laravel treats the decrypted values as the original state.
- Query Builder & Raw Queries – Because the helper intercepts Eloquent events, all result sets constructed via models (relations, pagination, API resources, etc.) receive decrypted data transparently. For direct
DB::select()usage, you can manually callEncryptionServiceto decrypt arrays if needed.
The helper never triggers encryption for tables that are not present (or not ACTIVE) in the CMS configuration. This keeps it safe to deploy broadly without code toggles.
Available Services
Although zero-integration is the default, you can resolve and use the internal services when needed:
| Service | Class | Responsibilities |
|---|---|---|
| Configuration | Ifabula\SevolaInterceptor\Services\ConfigService | Fetch, cache, and clear CMS configuration entries. |
| Encryption | Ifabula\SevolaInterceptor\Services\EncryptionService | Use Sevola SDK to encrypt/decrypt associative arrays, respecting algorithm/templates. |
| Model Manager | Ifabula\SevolaInterceptor\Services\ModelEncryptionManager | Core logic for handling model lifecycle events. |
| Query Interceptor (experimental) | Ifabula\SevolaInterceptor\Interceptors\QueryInterceptor | Low-level listener for query events. Disabled by default. |
All services are bound in the container as singletons, so you can resolve them with app(ConfigService::class), etc.
Usage Examples
1. Plain Eloquent usage (no code changes)
// Controller or service code
$user = App\Models\User::create([
'name' => 'Jane Doe',
'email' => 'jane@example.com', // encrypted in DB
'phone' => '555-1234', // encrypted in DB
]);
// Later …
$user = App\Models\User::find($user->id);
$user->email; // "jane@example.com" (decrypted automatically)
$user->phone; // "555-1234"
2. Manual encryption/decryption for raw arrays
use Ifabula\SevolaInterceptor\Services\ConfigService;
use Ifabula\SevolaInterceptor\Services\EncryptionService;
$configService = app(ConfigService::class);
$encryptionService = app(EncryptionService::class);
$config = $configService->getConfig('amplio_encrypt_dev', 'users');
if ($config && $config->isActive()) {
$payload = ['email' => 'john@example.com', 'phone' => '555-9999'];
$encrypted = $encryptionService->encryptData($payload, $config);
$decrypted = $encryptionService->decryptData($encrypted, $config);
}
3. Clearing configuration cache
app(ConfigService::class)->clearCache(); // all tables
app(ConfigService::class)->clearCache('db', 'table'); // specific table
4. Inspecting active configurations
$configs = app(ConfigService::class)->getAllActiveConfigs();
foreach ($configs as $config) {
printf(
"DB: %s | Table: %s | Columns: %s\n",
$config->databaseName,
$config->tableName,
implode(', ', $config->encryptedColumns)
);
}
5. Returning ciphertext for a specific query
use Ifabula\SevolaInterceptor\Support\SevolaContext;
use App\Models\TestEncryptionSmall;
// Default behaviour: decrypted values
$records = TestEncryptionSmall::all(); // plaintext attributes
// Optional: encrypted values for this call only
$encryptedRecords = SevolaContext::withReturnEncrypted(function () {
return TestEncryptionSmall::all(); // ciphertext attributes
});
// Manual push/pop when you cannot use the helper
SevolaContext::pushReturnEncrypted();
try {
$cipherRecords = TestEncryptionSmall::all();
} finally {
SevolaContext::pop();
}
Configuration Data Model
The helper expects a table (default mst_encryption_config) with the following structure. You normally maintain this via Sevola CMS, but the schema matters when you self-host the CMS database.
CREATE TABLE mst_encryption_config (
id INT PRIMARY KEY AUTO_INCREMENT,
config_name VARCHAR(255) NOT NULL,
database_name VARCHAR(255) NOT NULL,
table_name VARCHAR(255) NOT NULL,
encrypted_columns JSON NOT NULL,
status VARCHAR(50) NOT NULL DEFAULT 'ACTIVE',
encryption_algorithm VARCHAR(50) NOT NULL DEFAULT 'FF1',
created_at TIMESTAMP NULL,
updated_at TIMESTAMP NULL,
INDEX idx_db_table (database_name, table_name)
);
Example row:
{
"id": 7,
"config_name": "User PII",
"database_name": "amplio_encrypt_dev",
"table_name": "users",
"encrypted_columns": ["email", "phone", "ssn"],
"status": "ACTIVE",
"encryption_algorithm": "FF1"
}
Set status to INACTIVE to disable encryption for a table without removing it from the CMS.
Advanced Topics
Logging & Observability
SEVOLA_LOGGING=trueenables informational logs (provider loaded, response payload preview, etc.).SEVOLA_DEBUG=trueadds granular debug logs (config cache hits, attribute lists, encryption/decryption payloads).- Use
SEVOLA_LOG_CHANNELto route logs to dedicated channels (Stack, daily file, Slack, etc.).
Cache Strategy
- Configuration entries are cached per
(database, table)key. - Default TTL is 300 seconds. Increase it for noisy tables:
SEVOLA_CACHE_TTL=1800(30 minutes). - Call
ConfigService::clearCache()after editing entries in CMS to invalidate cache immediately.
Query Listener (experimental)
- Flip
SEVOLA_ENABLE_QUERY_LISTENER=trueto activateQueryInterceptor. - Currently logs executed SQL statements and checks if a config exists for the table.
- Intended as the staging point for deeper driver-level interception.
Working with Query Builder / Raw SQL
- Eloquent models auto-decrypt attributes. If you use raw
DB::select()calls, decrypt arrays manually viaEncryptionService. - Bulk CSV imports can pre-encrypt columns using the same service before calling
insert().
Troubleshooting
| Symptom | Possible Cause | Suggested Fix |
|---|---|---|
| Values remain encrypted when retrieved | CMS entry missing or inactive | Verify in Sevola CMS; clear helper cache |
| No encryption on save | CMS entry missing; event listeners not running | Check logs with debug mode enabled; ensure provider registered |
SEVOLA_API_KEY is not configured exception | .env missing key | Add key and run php artisan config:clear |
| Slow responses | Config cache TTL too low; logging too verbose | Increase SEVOLA_CACHE_TTL; disable debug logging |
| Need to force refresh after CMS change | Cache still holds old config | Call ConfigService::clearCache() |
Enable debug logging and watch storage/logs/laravel.log to diagnose issues quickly. You will see entries such as:
[2025-11-12 04:21:58] local.DEBUG: [Sevola] Global saving listener triggered {"model":"App\\Models\\User"}
[2025-11-12 04:21:58] local.DEBUG: [Sevola] Encrypting attributes during saving {"attributes":["email","phone"]}
[2025-11-12 04:21:58] local.DEBUG: [Sevola] Attributes decrypted {"model":"App\\Models\\User"}
FAQ
Do I need to modify my Eloquent models?
No. The helper intercepts Eloquent lifecycle events globally. Keep your models exactly as they are.
How do I disable encryption temporarily?
Mark the CMS entry as INACTIVE and clear the helper cache. Existing ciphertext stays encrypted in the database.
Can I encrypt new tables without deploying code?
Yes. Add the table to Sevola CMS, ensure the database user has access, and the helper will pick it up.
What about queue workers or scheduled jobs?
As long as the job boots Laravel normally (e.g., via Artisan commands), the service provider runs and encryption stays active.
Does this helper change database schemas?
No. The helper only transforms values going into/out of the database. Schema migrations are unchanged.
Contributing & Support
- 📦 Packagist: https://packagist.org/packages/ifabula/sevola-interceptor-helper
- 🧑💻 Source: https://gitlab.com/kasfi.tamiya/sevola-php-interceptor-helper
- 🧰 Related SDK: https://packagist.org/packages/ifabula/sevola-sdk-php
Issues and feature requests are welcome on GitLab. If you’re integrating into a large environment and need commercial support, please contact Ifabula directly.
Made with ❤️ by Ifabula.