2017-02-06 15 views
12

symfonyコンポーネントを使ってSilexでいくつかのプログラミングをしていますが、symfony/serializersymfony/validatorコンポーネントのバグが見つかりました。このデータは別のコンポーネントによって上書きされますか?

まず、私が達成しようとしていることを説明してから、コードに行きましょう。 私の目的は、逐次化指令や検証指令のような情報でクラスに注釈を付けることです。これらの注釈を読むことはCPUのコストがかかるので、私はそれらをメモリにキャッシュするのが好きです。この目的のために、Doctrine/Common/Cacheパッケージにmemcacheラッパーを使用しています。

私が直面する問題は、symfony/serializersymfony/validatorの両方が、クラス名をキーとしてキャッシュにメタデータを書き込むことです。後でメタデータを取得しようとすると、キャッシュに無効なメタデータ(Symfony\Component\Validator\Mapping\ClassMetadataまたはSymfony\Component\Serializer\Mapping\ClassMetadataInterfaceのインスタンス)があるため、例外がスローされます。

use Symfony\Component\Serializer\Annotation\Groups; 
use Symfony\Component\Validator\Constraints as Assert; 

class Foo 
{ 
    /** 
    * @var int 
    * @Assert\NotBlank(message="This field cannot be empty") 
    */ 
    private $someProperty; 

    /** 
    * @return int 
    * @Groups({"some_group"}) 
    */ 
    public function getSomeProperty() { 
     return $this->someProperty; 
    } 
} 


use Doctrine\Common\Annotations\AnnotationReader; 
use \Memcache as MemcachePHP; 
use Doctrine\Common\Cache\MemcacheCache as MemcacheWrapper; 

$loader = require_once __DIR__ . '/../vendor/autoload.php'; 

\Doctrine\Common\Annotations\AnnotationRegistry::registerLoader([$loader, 'loadClass']); 

$memcache = new MemcachePHP(); 

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

$cacheDriver = new MemcacheWrapper(); 
$cacheDriver->setMemcache($memcache); 

$app = new \Silex\Application(); 

$app->register(new Silex\Provider\SerializerServiceProvider()); 

$app['serializer.normalizers'] = function() use ($app, $cacheDriver) { 
    $classMetadataFactory = new Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactory(
     new Symfony\Component\Serializer\Mapping\Loader\AnnotationLoader(new AnnotationReader()), $cacheDriver); 

    return [new Symfony\Component\Serializer\Normalizer\GetSetMethodNormalizer($classMetadataFactory) ]; 
}; 

$app->register(new Silex\Provider\ValidatorServiceProvider(), [ 
    'validator.mapping.class_metadata_factory' => 
     new \Symfony\Component\Validator\Mapping\Factory\LazyLoadingMetadataFactory(
      new \Symfony\Component\Validator\Mapping\Loader\AnnotationLoader(new AnnotationReader()), 
      new \Symfony\Component\Validator\Mapping\Cache\DoctrineCache($cacheDriver) 
     ) 
]); 

$app->get('/', function(\Silex\Application $app) { 
    $foo = new Foo(); 

    $app['validator']->validate($foo); 
    $json = $app['serializer']->serialize($foo, 'json'); 

    return new \Symfony\Component\HttpFoundation\JsonResponse($json, \Symfony\Component\HttpFoundation\Response::HTTP_OK, [], true); 
}); 

$app->error(function (\Exception $e, \Symfony\Component\HttpFoundation\Request $request, $code) { 
    return new \Symfony\Component\HttpFoundation\Response('We are sorry, but something went terribly wrong.' . $e->getMessage()); 
}); 

$app->run(); 

あなたは致命的なエラーが発生します。この例を実行した後:

後は(その大きい場合には、私は可能な限り小さく作ってみました申し訳ありません)reproductible例です。 誰かが私がここで間違いを犯さないことを確認できますか?

現在のところ、この問題を回避するには、キャッシュキーに名前空間を使用するDoctrineCacheクラスを書き直してください。その仕事は、私はその醜いと思います。

答えて

2

私はあなたがする必要があると思います2つの別のCacheDriversです。名前空間の使用方法については、https://github.com/doctrine/cache/blob/master/lib/Doctrine/Common/Cache/CacheProvider.phpを参照してください。

あなたは可能性:

$validatorCacheDriver = new MemcacheWrapper(); 
$validatorCacheDriver->setMemcache($memcache); 
$validatorCacheDriver->setNamespace('symfony_validator'); 

$serializerCacheDriver = new MemcacheWrapper(); 
$serializerCacheDriver->setMemcache($memcache); 
$serializerCacheDriver->setNamespace('symfony_serializer'); 

// note that the two drivers are using the same memcache instance, 
// so only one connection will be used. 

$app['serializer.normalizers'] = function() use ($app, $serializerCacheDriver) { 
    $classMetadataFactory = new Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactory(
     new Symfony\Component\Serializer\Mapping\Loader\AnnotationLoader(new AnnotationReader()), $serializerCacheDriver); 

    return [new Symfony\Component\Serializer\Normalizer\GetSetMethodNormalizer($classMetadataFactory) ]; 
}; 

$app->register(new Silex\Provider\ValidatorServiceProvider(), [ 
    'validator.mapping.class_metadata_factory' => 
     new \Symfony\Component\Validator\Mapping\Factory\LazyLoadingMetadataFactory(
      new \Symfony\Component\Validator\Mapping\Loader\AnnotationLoader(new AnnotationReader()), 
      new \Symfony\Component\Validator\Mapping\Cache\DoctrineCache($validatorCacheDriver) 
     ) 
]); 

私が唯一の解決策では、いくつかの役割を果たしパーツを表示するためのコードをトリミングしました。私はこれが助けて欲しい!

関連する問題