Resolver conflito entre validator e serializer no silex

Por Jean Hertel, 15/03/2017

symfony , silex , validator , serializar , cache , php

Se você leu meus artigos anteriores sobre como configurar o Serializer e o Validator do symfony para utilizarem cache, certamente você já notou a grande diferença de performance que isso traz. Porem, você também deve ter notado que ao utilizar o validator e o serializer em uma mesma classe você recebe erro fatal. Algo como:

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

/* Ou ainda */
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

Isso ocorre porque tanto o serializer como o validator escrevem no cache as instancias de metada utilizando o nome da classe como chave. Ao extrair novamente o resultado do cache, ocorre um erro fatal, pois o objeto não é do tipo esperado.

A maneira mais simples de resolver este problema é adicionando um namespace diferente para cada um dos caches. A classe base dos caches do Doctrine é Doctrine\Common\Cache\CacheProvider. Esta classe possui um método chamado setNamespace que lhe permite fazer essa diferença.

Para evitar a duplicação na conexão com o servidor de cache você deve primeiro conectar e depois criar as instancias do provider. O snippet de código a seguir trata corretamente esta situação:

<?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');

Agora você pode usar livremente o serializer e o validator sem erros :)