Resolving conflict between validator and serializer in silex

By Jean Hertel, 15/03/2017, modified 24/03/2017, in category Tips

Cache, PHP, Serializar, Silex, Symfony, Validator

If you have read my previous articles on how to configure symfony Serializer and Validator to use cache, you have certainly noticed the great difference in performance that this brings. However, you should also have noticed that when using the validator and the serializer in the same class you receive fatal error.

Fatal error: Uncaught Error: Call to undefined method Symfony\Component\Validator\Mapping\ClassMetadata::getAttributesMetadata() in /var/www/test/vendor/symfony/serializer/Normalizer/AbstractObjectNormalizer.php on line 72

/* Or */
Fatal error: Uncaught TypeError: Argument 1 passed to Symfony\Component\Validator\Mapping\Factory\LazyLoadingMetadataFactory::mergeConstraints() must be an instance of Symfony\Component\Validator\Mapping\ClassMetadata, instance of Symfony\Component\Serializer\Mapping\ClassMetadata given, called in /var/www/test/vendor/symfony/validator/Mapping/Factory/LazyLoadingMetadataFactory.php on line 104 and defined in C:\www\xpath\vendor\symfony\validator\Mapping\Factory\LazyLoadingMetadataFactory.php on line 129

This is because both the serializer and the validator cached the metadata instances using the class name as the key. When you re-extract the result from the cache, a fatal error occurs because the object is not of the expected type.

The simplest way to solve this problem is to add a different namespace for each of the caches. The base class of Doctrine caches is Doctrine\Common\Cache\CacheProvider. This class has a method called setNamespace that allows you to make this difference.

To avoid duplicate connection to the cache server you must first connect and then create the provider instances. The following code snippet correctly handles this situation:

<?php
use \Memcache as MemcachePHP;
use Doctrine\Common\Cache\MemcacheCache as MemcacheWrapper;

$memcache = new MemcachePHP();

if (! $memcache->connect('localhost', '11211')) {
    throw new \Exception('Unable to connect to memcache server');
}

$cacheDriverSerializer = new MemcacheWrapper();
$cacheDriverSerializer->setMemcache($memcache);
$cacheDriverSerializer->setNamespace('SerializerNameSpace');

$cacheDriverValidator = new MemcacheWrapper();
$cacheDriverValidator->setMemcache($memcache);
$cacheDriverValidator->setNamespace('ValidatorNameSpace');

Now you can freely use serializer and validator without errors :)