nowo-tech / doctrine-encrypt-bundle
Encrypt Doctrine entity fields at rest with Halite or Defuse. Symfony 7|8 bundle for field-level encryption, GDPR-friendly, multiple keys, key rotation.
Package info
github.com/nowo-tech/DoctrineEncryptBundle
Type:symfony-bundle
pkg:composer/nowo-tech/doctrine-encrypt-bundle
Fund package maintenance!
Requires
- php: >=8.1
- doctrine/orm: ^2.15 || ^3.0
- paragonie/halite: ^5.1
- paragonie/sodium_compat: ^1.20 || ^2.0
- symfony/config: ^7.0 || ^8.0
- symfony/dependency-injection: ^7.0 || ^8.0
- symfony/http-kernel: ^7.0 || ^8.0
- symfony/property-access: ^7.0 || ^8.0
- symfony/var-exporter: ^7.0 || ^8.0
- symfony/yaml: ^7.0 || ^8.0
- twig/twig: ^3.2
Requires (Dev)
- defuse/php-encryption: ^2.1
- friendsofphp/php-cs-fixer: ^3.0
- phpunit/phpunit: ^10.0 || ^11.0
- symfony/cache: ^7.0 || ^8.0
Suggests
- ext-sodium: Required to use Halite encryption library
- defuse/php-encryption: Alternative to Halite for encryption
This package is auto-updated.
Last update: 2026-03-27 17:23:14 UTC
README
Symfony bundle to encrypt Doctrine entity fields at rest using Halite or Defuse—audited libraries, no custom crypto. For Symfony 7 and 8 · PHP 8.1+. Suits GDPR and compliance (e.g. Art. 32); supports key rotation and Nowo\AnonymizedBundle for anonymization and erasure.
⭐ Found this useful? Install from Packagist · Give it a star on GitHub so more developers can find it.
Table of contents
- Quick search terms
- Features
- Installation
- Configuration
- Usage
- Documentation
- Requirements
- Demo
- Development
- License & author
Quick search terms
Looking for Doctrine encryption, encrypt entity fields, Halite Symfony, Defuse encryption, field-level encryption, encrypt database column, Symfony encrypt attribute, Doctrine Encrypted? You're in the right place.
Features
- ✅ Encrypt and decrypt entity properties with a single attribute
- ✅ Multiple encryptor configs — e.g.
personal_data(Halite) andfinancial_data(Defuse) in the same app, each with its own key - ✅ Halite and Defuse — audited crypto libraries, no custom algorithms
- ✅ Transparent: encrypt on persist/update, decrypt on load
- ✅ EncryptUtil — programmatic
encrypt()/decrypt()with optional config name (default or e.g.financial_data) - ✅ MaskUtil — mask sensitive values in PHP (e.g. show only last N chars); usable in services
- ✅ Twig filters —
|decrypt(decrypt in templates; optional config:{{ value|decrypt }}or{{ value|decrypt('financial_data') }}) and|mask(mask for display:{{ value|mask(4) }}or{{ value|decrypt|mask(4) }}) - ✅ Works with embedded entities and inheritance
- ✅ Console commands: status, generate secret key, encrypt/decrypt database, rotate keys (backup, decrypt, change keys, re-encrypt with confirmations)
- ✅ Key rotation — one command or manual steps; combinable with Nowo\AnonymizedBundle for GDPR-compliant anonymization and erasure
- ✅ Symfony Flex recipe (register bundle + config; see docs/INSTALLATION.md)
- ✅ Compatible with Symfony 7 and 8 and Doctrine ORM 2.x and 3.x
- ✅ Compatible with FrankenPHP (HTTP runtime and optional worker mode; demos default to
APP_ENV=devwith Caddyfile.dev, i.e. no PHP worker — see docs/DEMO-FRANKENPHP.md and Installation → FrankenPHP)
Installation
composer require nowo-tech/doctrine-encrypt-bundle
With Symfony Flex, the recipe (when enabled) registers the bundle and creates the config file automatically. Without Flex, see docs/INSTALLATION.md for manual steps.
Manual registration in config/bundles.php:
<?php return [ // ... Nowo\DoctrineEncryptBundle\NowoDoctrineEncryptBundle::class => ['all' => true], ];
Configuration
Create config/packages/nowo_doctrine_encrypt.yaml. You can use one encryptor (legacy) or multiple named configs (recommended).
Multiple configs (recommended)
Use different encryptors and keys per kind of data (e.g. personal vs financial):
nowo_doctrine_encrypt: default_config: personal_data # used when attribute has no config or uses "default" configs: personal_data: encryptor_class: Halite secret_directory_path: '%kernel.project_dir%' financial_data: encryptor_class: Defuse secret_directory_path: '%kernel.project_dir%'
Defuse: composer require defuse/php-encryption ^2.1
Key files: one per config, e.g. .Halite.personal_data.key, .Defuse.financial_data.key in the config’s secret_directory_path. Add to .gitignore:
.Halite.key .Defuse.key .Halite.*.key .Defuse.*.key
Generate keys: php bin/console doctrine:encrypt:generate-secret-key (creates missing Halite/Defuse keys for all configs, or pass a config alias). See docs/CONFIGURATION.md and docs/COMMANDS.md.
Single encryptor (one config)
Use one entry under configs (e.g. default):
nowo_doctrine_encrypt: default_config: default configs: default: encryptor_class: Halite # or Defuse secret_directory_path: '%kernel.project_dir%'
Key file: .Halite.default.key (or .Defuse.default.key). Full options: docs/CONFIGURATION.md.
Usage
Mark entity properties with the Encrypted attribute. Use no argument (or "default") for the default config, or the config name when using multiple configs:
use Nowo\DoctrineEncryptBundle\Configuration\Encrypted; #[ORM\Entity] class User { #[ORM\Column(type: 'string')] #[Encrypted] // or #[Encrypted('default')] — uses default_config private ?string $email = null; }
With multiple configs, pass the config alias per property:
#[ORM\Column(type: 'string')] #[Encrypted('personal_data')] private ?string $email = null; #[ORM\Column(type: 'string')] #[Encrypted('financial_data')] private ?string $iban = null;
Values are encrypted on persist/update and decrypted on load. For programmatic use: EncryptUtil (encrypt/decrypt) and MaskUtil (mask for display). In Twig use the |decrypt and |mask filters. See docs/USAGE.md for EncryptUtil, MaskUtil, Twig filters, embedded entities, and inheritance.
Documentation
Additional documentation
- Demo with FrankenPHP (development and production)
- Example
- Commands
- Key rotation
- Demo
- Custom encryptor
Requirements
- PHP >= 8.1
- Symfony 7 or 8 (^7.0 || ^8.0). Current releases of this package require Symfony 7 or 8 (see
composer.json). - Doctrine ORM ^2.15 || ^3.0
- paragonie/halite (included); for Defuse:
defuse/php-encryption ^2.1 - ext-sodium recommended for Halite (or sodium_compat)
See docs/INSTALLATION.md and docs/UPGRADING.md for compatibility notes.
Demo
Demos for Symfony 7 and 8 are in demo/symfony7, demo/symfony8. Each runs with FrankenPHP and Caddy (HTTP on port 80 in the container). docker-compose defaults to APP_ENV=dev, so the entrypoint uses Caddyfile.dev (no PHP worker; changes visible on refresh). Worker mode is for a production-style setup — docs/DEMO-FRANKENPHP.md. Default host ports: 8007 (symfony7), 8008 (symfony8) via PORT. Quick start: docs/DEMO.md.
Development
Run tests and QA with Docker: make up && make install && make test (or make test-coverage, make qa). Without Docker: composer install && composer test. See Makefile for all targets.
Tests and coverage
- Tests: PHPUnit (unit and functional suites)
- PHP: 96.14%
License
The MIT License (MIT). Please see LICENSE for more information.
Author
Created by Héctor Franco Aceituno at Nowo.tech