ekino/data-protection-bundle
Installation:
composer require ekino/data-protection-bundle
Register the bundle in config/bundles.php (Symfony 4+) or AppKernel.php (Symfony 2/3).
Basic Configuration (config/packages/ekino_data_protection.yaml):
ekino_data_protection:
encryption_key: '%env(ENCRYPTION_KEY)%' # 32-byte key for AES-256
default_algorithm: 'AES-256-CBC' # Default encryption algorithm
Ensure ENCRYPTION_KEY is set in .env (e.g., ENCRYPTION_KEY=your_32_byte_base64_encoded_key).
First Use Case: Encrypt/decrypt a string via a service:
use Ekino\DataProtectionBundle\Service\DataProtector;
class MyService {
public function __construct(private DataProtector $protector) {}
public function protectData(string $data): string {
return $this->protector->encrypt($data);
}
public function unprotectData(string $encryptedData): string {
return $this->protector->decrypt($encryptedData);
}
}
Field-Level Encryption: Use the bundle’s Doctrine listeners to auto-encrypt/decrypt entity fields:
ekino_data_protection:
entities:
App\Entity\SensitiveData:
fields:
- creditCardNumber
- ssn
The bundle handles encryption/decryption transparently during prePersist/preUpdate.
API Payload Protection: Protect sensitive data in API responses using serializer groups:
#[Groups(['api'])]
#[Ekino\DataProtectionBundle\Annotation\Protected]
private string $passwordHash;
Configure the serializer to use the protected group in config/packages/serializer.yaml.
Custom Encryption Logic:
Extend the DataProtector service or create a custom protector:
class CustomProtector extends DataProtector {
public function encryptWithMetadata(string $data, array $metadata): string {
// Custom logic (e.g., add timestamps, IVs)
return parent::encrypt($data);
}
}
Bind it in services.yaml:
services:
App\Service\CustomProtector:
arguments:
$encryptionKey: '%env(ENCRYPTION_KEY)%'
$algorithm: 'AES-256-CBC'
Bulk Operations:
Use the DataProtector for batch processing (e.g., CSV imports/exports):
$protector = $this->container->get(DataProtector::class);
$encryptedData = array_map([$protector, 'encrypt'], $plainDataArray);
@Assert\Type or custom accessors.hash() on encrypted strings).DataProtector in unit tests:
$this->mockBuilder(DataProtector::class)
->disableOriginalConstructor()
->getMock()
->method('encrypt')
->willReturn('encrypted_placeholder');
Key Management:
.env or a secrets manager (e.g., AWS Secrets Manager).openssl rand -base64 32
Algorithm Quirks:
ekino_data_protection.yaml:
default_algorithm: 'AES-256-GCM'
Doctrine Caveats:
TEXT instead of VARCHAR(255)).fetch="EAGER" or DQL JOIN:
$query->addSelect('PARTIAL s.0->creditCardNumber'); // Partial load
Serialization Issues:
+ in Base64). Use json_encode($data, JSON_UNESCAPED_UNICODE).@Protected, ensure the serializer is configured to handle encrypted data in both directions.Performance:
Validation Errors:
.env).ekino_data_protection:
debug: true
Doctrine Errors:
ekino_data_protection.yaml matches the entity property.@ORM\Column(type="text") for encrypted fields.Logging:
monolog:
handlers:
data_protection:
type: stream
path: "%kernel.logs_dir%/data_protection.log"
level: debug
channels: ["data_protection"]
ekino_data_protection:
logger_channel: "data_protection"
Custom Encryption Algorithms:
Implement Ekino\DataProtectionBundle\Algorithm\AlgorithmInterface:
class MyAlgorithm implements AlgorithmInterface {
public function encrypt(string $data, string $key): string { /* ... */ }
public function decrypt(string $data, string $key): string { /* ... */ }
}
Register it in services.yaml:
services:
App\Algorithm\MyAlgorithm:
tags: ['ekino_data_protection.algorithm']
Pre/Post-Encryption Hooks: Use Symfony’s event system to intercept encryption/decryption:
// config/services.yaml
Ekino\DataProtectionBundle\EventListener\DataProtectionListener:
tags:
- { name: kernel.event_listener, event: ekino.data_protection.encrypt, method: onEncrypt }
- { name: kernel.event_listener, event: ekino.data_protection.decrypt, method: onDecrypt }
Custom Metadata: Attach metadata to encrypted data (e.g., expiration timestamps):
$metadata = ['expires_at' => time() + 3600];
$protectedData = $protector->encryptWithMetadata($data, $metadata);
Retrieve metadata during decryption:
$decrypted = $protector->decryptWithMetadata($protectedData);
$metadata = $decrypted['metadata'];
How can I help you explore Laravel packages today?