Эти данные перезаписываются другим компонентом?

Я занимаюсь программированием в Silex с помощью компонентов Symfony и думаю, что нашел ошибку в symfony/serializer и symfony/validator компоненты.

Сначала позвольте мне объяснить, чего я хочу достичь, а затем перейдем к коду.
Моя цель — аннотировать класс информацией, такой как директивы сериализации, а также директивы валидации. Поскольку чтение этих аннотаций может стоить немного ресурсов процессора, я люблю кэшировать их в памяти. Для этого я использую оболочку memcache в Doctrine/Common/Cache пакет.

Проблема, с которой я сталкиваюсь, заключается в том, что оба symfony/serializer и symfony/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();

После запуска этого примера вы получаете фатальные ошибки.
Кто-нибудь может подтвердить, что я здесь не ошибаюсь?

В настоящее время мой обходной путь для этого переписать DoctrineCache класс, использующий пространство имен для ключей кэша. Это работает, но я думаю, что это некрасиво.

12

Решение

Я думаю, что вам нужно сделать, это два отдельных 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)
)
]);

Я обрезал код, чтобы показать только те части, которые играют определенную роль в решении. Надеюсь, это поможет!

2

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]