此数据是不是被另一个组件覆盖?

Posted

技术标签:

【中文标题】此数据是不是被另一个组件覆盖?【英文标题】:Is this data being overwritten by another component?此数据是否被另一个组件覆盖? 【发布时间】:2017-06-23 19:27:46 【问题描述】:

我正在使用 symfony 组件在 Silex 中进行一些编程,我想我发现了 symfony/serializersymfony/validator 组件的错误。

首先让我解释一下我训练要实现的目标,然后我们来看代码。 我的目标是用序列化指令和验证指令等信息来注释一个类。由于读取这些注释可能会消耗很少的 CPU,因此我喜欢将它们缓存在内存中。为此,我在 Doctrine/Common/Cache 包中使用了 memcache 包装器。

我面临的问题是symfony/serializersymfony/validator 都使用类名作为键将元数据写入缓存。当他们稍后尝试检索元数据时,他们会抛出异常,因为缓存中有无效的元数据,Symfony\Component\Validator\Mapping\ClassMetadataSymfony\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 类,使用缓存键的命名空间。它可以工作,但我认为它很丑。

【问题讨论】:

【参考方案1】:

我认为你需要做的是两个独立的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)
        )
]);

我已经修剪了代码,只显示在解决方案中发挥作用的部分。我希望这会有所帮助!

【讨论】:

以上是关于此数据是不是被另一个组件覆盖?的主要内容,如果未能解决你的问题,请参考以下文章

Notification PendingIntent Intent extras 被另一个通知覆盖

如果被另一个元素覆盖,则响应 CSS 悬停选择器

如何计算被另一个多边形覆盖的多边形的百分比

UIViewController 被另一个全屏视图控制器覆盖,但没有从层次结构中删除

可以在仅部分覆盖的情况下执行单字节指令吗?

Symfony - 如何覆盖不在捆绑包中的供应商组件