I\'m using Symfony 2 with Doctrine 2.
I need to encrypt a field in my entity using an encryption service, and I\'m wondering where should I put this logic.
I\'m
To expand on richsage and targnation's great answers, one way to inject a dependency (e.g., cypto service) into a custom Doctrine mapping type, could be to use a static property and setter:
// MyBundle/Util/Crypto/Types/EncryptedString.php
class EncryptedString extends StringType
{
/** @var \MyBundle\Util\Crypto */
protected static $crypto;
public static function setCrypto(Crypto $crypto)
{
static::$crypto = $crypto;
}
public function convertToDatabaseValue($value, AbstractPlatform $platform)
{
$value = parent::convertToDatabaseValue($value, $platform);
return static::$crypto->encrypt($value);
}
public function convertToPHPValue($value, AbstractPlatform $platform)
{
$value = parent::convertToPHPValue($value, $platform);
return static::$crypto->decrypt($value);
}
public function getName()
{
return 'encrypted_string';
}
}
Configuration would look like this:
// MyBundle/MyBundle.php
class MyBundle extends Bundle
{
public function boot()
{
/** @var \MyBundle\Util\Crypto $crypto */
$crypto = $this->container->get('mybundle.util.crypto');
EncryptedString::setCrypto($crypto);
}
}
# app/Resources/config.yml
doctrine:
dbal:
types:
encrypted_string: MyBundle\Util\Crypto\Types\EncryptedString
# MyBundle/Resources/config/services.yml
services:
mybundle.util.crypto:
class: MyBundle\Util\Crypto
arguments: [ %key% ]
I don't know if it's the right way at all, but I implemented this recently by creating a custom mapping type, as per the Doctrine docs. Something like the following:
class EncryptedStringType extends TextType
{
const MYTYPE = 'encryptedstring'; // modify to match your type name
public function convertToPHPValue($value, AbstractPlatform $platform)
{
return base64_decode($value);
}
public function convertToDatabaseValue($value, AbstractPlatform $platform)
{
return base64_encode($value);
}
public function getName()
{
return self::MYTYPE;
}
}
I registered this type in my bundle class:
class MyOwnBundle extends Bundle
{
public function boot()
{
$em = $this->container->get("doctrine.orm.entity_manager");
try
{
Type::addType("encryptedstring", "My\OwnBundle\Type\EncryptedStringType");
$em->
getConnection()->
getDatabasePlatform()->
registerDoctrineTypeMapping("encryptedstring", "encryptedstring");
} catch (\Doctrine\DBAL\DBALException $e)
{
// For some reason this exception gets thrown during
// the clearing of the cache. I didn't have time to
// find out why :-)
}
}
}
and then I was able to reference it when creating my entities, eg:
/**
* @ORM\Column(type="encryptedstring")
* @Assert\NotBlank()
*/
protected $name;
This was a quick implementation, so I'd be interested to know the correct way of doing it. I presume also that your encryption service is something available from the container; I don't know how feasible/possible it would be to pass services into custom types this way either... :-)
richsage's answer was pretty good, except I wouldn't register the custom type in the bundle class file. It's recommended that you use the config.yml like so:
# ./app/config/confi
doctrine:
dbal:
driver: "%database_driver%"
{{ etc, etc }}
types:
encrypted_string: MyCompany\MyBundle\Type\EncryptedStringType
Then just make sure in your EncryptedStringType class you specify the getName function to return encrypted_string.
Now in your model definition (or annotation) you can use the encrypted_string type.