[Validator] Added support for metadata caching

This commit is contained in:
Bernhard Schussek 2010-07-04 17:31:01 +02:00
parent 1c7b459776
commit 8c9f9de086
3 changed files with 125 additions and 14 deletions

View File

@ -0,0 +1,36 @@
<?php
namespace Symfony\Components\Validator\Mapping\Cache;
use Symfony\Components\Validator\Mapping\ClassMetadata;
/**
* Persists ClassMetadata instances in a cache
*
* @author Bernhard Schussek <bernhard.schussek@symfony-project.com>
*/
interface CacheInterface
{
/**
* Returns whether metadata for the given class exists in the cache
*
* @param string $class
*/
public function has($class);
/**
* Returns the metadata for the given class from the cache
*
* @param string $class
* @return ClassMetadata
*/
public function read($class);
/**
* Stores a class metadata in the cache
*
* @param $class
* @param $metadata
*/
public function write(ClassMetadata $metadata);
}

View File

@ -3,16 +3,33 @@
namespace Symfony\Components\Validator\Mapping;
use Symfony\Components\Validator\Mapping\Loader\LoaderInterface;
use Symfony\Components\Validator\Mapping\Cache\CacheInterface;
/**
* Implementation of ClassMetadataFactoryInterface
*
* @author Bernhard Schussek <bernhard.schussek@symfony-project.com>
*/
class ClassMetadataFactory implements ClassMetadataFactoryInterface
{
/**
* The loader for loading the class metadata
* @var LoaderInterface
*/
protected $loader;
/**
* The cache for caching class metadata
* @var CacheInterface
*/
protected $cache;
protected $loadedClasses = array();
public function __construct(LoaderInterface $loader)
public function __construct(LoaderInterface $loader, CacheInterface $cache = null)
{
$this->loader = $loader;
$this->cache = $cache;
}
public function getClassMetadata($class)
@ -20,21 +37,29 @@ class ClassMetadataFactory implements ClassMetadataFactoryInterface
$class = ltrim($class, '\\');
if (!isset($this->loadedClasses[$class])) {
$metadata = new ClassMetadata($class);
if ($this->cache !== null && $this->cache->has($class)) {
$this->loadedClasses[$class] = $this->cache->read($class);
} else {
$metadata = new ClassMetadata($class);
// Include constraints from the parent class
if ($parent = $metadata->getReflectionClass()->getParentClass()) {
$metadata->mergeConstraints($this->getClassMetadata($parent->getName()));
// Include constraints from the parent class
if ($parent = $metadata->getReflectionClass()->getParentClass()) {
$metadata->mergeConstraints($this->getClassMetadata($parent->getName()));
}
// Include constraints from all implemented interfaces
foreach ($metadata->getReflectionClass()->getInterfaces() as $interface) {
$metadata->mergeConstraints($this->getClassMetadata($interface->getName()));
}
$this->loader->loadClassMetadata($metadata);
$this->loadedClasses[$class] = $metadata;
if ($this->cache !== null) {
$this->cache->write($metadata);
}
}
// Include constraints from all implemented interfaces
foreach ($metadata->getReflectionClass()->getInterfaces() as $interface) {
$metadata->mergeConstraints($this->getClassMetadata($interface->getName()));
}
$this->loader->loadClassMetadata($metadata);
$this->loadedClasses[$class] = $metadata;
}
return $this->loadedClasses[$class];

View File

@ -55,6 +55,56 @@ class ClassMetadataFactoryTest extends \PHPUnit_Framework_TestCase
$this->assertEquals($constraints, $metadata->getConstraints());
}
public function testWriteMetadataToCache()
{
$cache = $this->getMock('Symfony\Components\Validator\Mapping\Cache\CacheInterface');
$factory = new ClassMetadataFactory(new TestLoader(), $cache);
$tester = $this;
$constraints = array(
new ConstraintA(array('groups' => array('Default', 'EntityParent'))),
);
$cache->expects($this->once())
->method('has')
->with($this->equalTo(self::PARENTCLASS))
->will($this->returnValue(false));
$cache->expects($this->once())
->method('write')
->will($this->returnCallback(function($metadata) use ($tester, $constraints) {
$tester->assertEquals($constraints, $metadata->getConstraints());
}));
$metadata = $factory->getClassMetadata(self::PARENTCLASS);
$this->assertEquals(self::PARENTCLASS, $metadata->getClassName());
$this->assertEquals($constraints, $metadata->getConstraints());
}
public function testReadMetadataFromCache()
{
$loader = $this->getMock('Symfony\Components\Validator\Mapping\Loader\LoaderInterface');
$cache = $this->getMock('Symfony\Components\Validator\Mapping\Cache\CacheInterface');
$factory = new ClassMetadataFactory($loader, $cache);
$tester = $this;
$metadata = new ClassMetadata(self::PARENTCLASS);
$metadata->addConstraint(new ConstraintA());
$loader->expects($this->never())
->method('loadClassMetadata');
$cache->expects($this->once())
->method('has')
->with($this->equalTo(self::PARENTCLASS))
->will($this->returnValue(true));
$cache->expects($this->once())
->method('read')
->will($this->returnValue($metadata));
$this->assertEquals($metadata,$factory->getClassMetadata(self::PARENTCLASS));
}
}
class TestLoader implements LoaderInterface