aeliot/doctrine-encrypted-bundle
Symfony bundle that adds Doctrine column types for encrypting individual database fields. Install via Composer, configure your key and mappings, and store encrypted values transparently. Notes on DB charset/collation (utf8mb4) for reliable sizing.
Installation
composer require aeliot/doctrine-encrypted-bundle
Ensure your config/packages.php includes the bundle (automatically loaded via autoloader).
Configure Encryption Key
Add a DOCTRINE_ENCRYPTED_BUNDLE entry to your .env:
DOCTRINE_ENCRYPTED_BUNDLE_KEY=your-32-byte-base64-encoded-key-here
Generate a key using OpenSSL:
openssl rand -base64 32
First Use Case: Encrypt a Column Update an entity field to use the encrypted type:
use Aeliot\DoctrineEncryptedBundle\DBAL\Types\EncryptedType;
#[ORM\Entity]
class User
{
#[ORM\Column(type: EncryptedType::NAME)]
private string $sensitiveData;
}
Run migrations (php bin/console doctrine:migrations:diff + php bin/console doctrine:migrations:migrate).
Selective Encryption
Apply EncryptedType only to sensitive fields (e.g., password, credit_card, api_keys).
Avoid encrypting frequently queried columns (impacts performance).
Querying Encrypted Data Use standard Doctrine queries—decryption happens transparently:
$user = $entityManager->getRepository(User::class)->find($id);
// $user->sensitiveData is decrypted automatically
Bulk Operations
For batch inserts/updates, leverage Doctrine’s BulkOperations or QueryBuilder:
$qb = $entityManager->createQueryBuilder();
$qb->update(User::class, 'u')
->set('u.sensitiveData', ':data')
->where('u.id = :id')
->setParameter('data', $encryptedValue)
->setParameter('id', $userId)
->getQuery()
->execute();
Custom Encryption Logic Extend the base type for per-field encryption (e.g., AES-256 vs. ChaCha20):
use Aeliot\DoctrineEncryptedBundle\DBAL\Types\EncryptedType;
class CustomEncryptedType extends EncryptedType
{
protected function getEncryptionAlgorithm(): string
{
return 'aes-256-cbc';
}
}
Register in services.yaml:
services:
App\DBAL\Types\CustomEncryptedType:
tags: ['doctrine.type']
Key Management
doctrine:query to dump/load encrypted values).Performance Overhead
doctrine:query-sql to identify bottlenecks.VARCHAR columns with length < 32 (padding overhead).Migration Pitfalls
public function up(SchemaManagerInterface $manager): void
{
$connection = $manager->getConnection();
$connection->executeStatement(
'UPDATE users SET sensitive_data = ENCRYPT(sensitive_data, :key)',
['key' => $this->getEncryptionKey()]
);
}
utf8mb4_unicode_ci (required for binary-safe operations).Debugging
# config/packages/dev/doctrine.yaml
doctrine:
dbal:
logging: true
profiling: true
Partial Encryption
Use EncryptedType alongside JsonType for nested encrypted objects:
#[ORM\Column(type: 'json')]
private array $encryptedJsonData;
Note: Manual serialization/deserialization required.
Caching Encrypted Values
Cache decrypted values in the entity’s __construct() to avoid repeated decryption:
private ?string $decryptedSensitiveData = null;
public function getSensitiveData(): string
{
if ($this->decryptedSensitiveData === null) {
$this->decryptedSensitiveData = $this->sensitiveData; // Auto-decrypted
}
return $this->decryptedSensitiveData;
}
Testing Mock the encryption key in tests:
$container->setParameter('doctrine_encrypted_bundle.key', 'test-key-32bytesbase64');
Use doctrine:fixtures:load to populate test data with encrypted values.
Backup Strategy
php bin/console doctrine:query-sql "SELECT id, sensitive_data FROM users" > backup.sql
Extension Points
EncryptedType to integrate with AWS KMS or HashiCorp Vault.How can I help you explore Laravel packages today?