Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Doctrine Encrypted Bundle Laravel Package

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.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Installation

    composer require aeliot/doctrine-encrypted-bundle
    

    Ensure your config/packages.php includes the bundle (automatically loaded via autoloader).

  2. 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
    
  3. 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).


Implementation Patterns

Workflows

  1. Selective Encryption Apply EncryptedType only to sensitive fields (e.g., password, credit_card, api_keys). Avoid encrypting frequently queried columns (impacts performance).

  2. Querying Encrypted Data Use standard Doctrine queries—decryption happens transparently:

    $user = $entityManager->getRepository(User::class)->find($id);
    // $user->sensitiveData is decrypted automatically
    
  3. 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();
    
  4. 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']
    

Gotchas and Tips

Pitfalls

  1. Key Management

    • Never hardcode keys in version control. Use environment variables or a secrets manager.
    • Rotate keys periodically (requires re-encrypting data; use doctrine:query to dump/load encrypted values).
  2. Performance Overhead

    • Encryption adds ~10–50ms per field. Benchmark with doctrine:query-sql to identify bottlenecks.
    • Avoid encrypting VARCHAR columns with length < 32 (padding overhead).
  3. Migration Pitfalls

    • Existing data: Migrate encrypted columns via a custom migration:
      public function up(SchemaManagerInterface $manager): void
      {
          $connection = $manager->getConnection();
          $connection->executeStatement(
              'UPDATE users SET sensitive_data = ENCRYPT(sensitive_data, :key)',
              ['key' => $this->getEncryptionKey()]
          );
      }
      
    • Collation/Charset: Ensure tables use utf8mb4_unicode_ci (required for binary-safe operations).
  4. Debugging

    • Decryption failures: Check for:
      • Invalid key format (must be 32-byte base64).
      • Corrupted data (e.g., truncated strings).
    • Enable Doctrine logging:
      # config/packages/dev/doctrine.yaml
      doctrine:
          dbal:
              logging: true
              profiling: true
      

Tips

  1. Partial Encryption Use EncryptedType alongside JsonType for nested encrypted objects:

    #[ORM\Column(type: 'json')]
    private array $encryptedJsonData;
    

    Note: Manual serialization/deserialization required.

  2. 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;
    }
    
  3. 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.

  4. Backup Strategy

    • Pre-migration: Export encrypted data before key rotation:
      php bin/console doctrine:query-sql "SELECT id, sensitive_data FROM users" > backup.sql
      
    • Post-migration: Re-import with the new key.
  5. Extension Points

    • Custom Cipher: Override EncryptedType to integrate with AWS KMS or HashiCorp Vault.
    • Field-Level Policies: Combine with Symfony’s Voters to restrict encryption by user role.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
besmartand-pro/php-quality-config
sentix/ai-chatbot
terminal42/code-quality-tools
codifyo/ts-generator-bundle
testo/fiber
mintobit/jobqueue
a4sex/maintenance-bundle
a4sex/entity-date-update
a4sex/client-identifier
a4sex/base-utilites
a4sex/key-value-storage
a4sex/micro-status
chilldev/dependency-injection-extra
datinglibre/datinglibre-app-api
biberltd/corebundle
bricre/symfony-bundle-test
biberltd/logbundle
dominium/http-adapter-bundle
dominium/google-analytics
a4sex/auto-clean-entity