Skip to content

Commit

Permalink
Cache when there is no metadata for a class
Browse files Browse the repository at this point in the history
  • Loading branch information
adrienbrault committed Oct 18, 2013
1 parent 24c5fc5 commit 32458c4
Show file tree
Hide file tree
Showing 3 changed files with 138 additions and 12 deletions.
46 changes: 34 additions & 12 deletions src/Metadata/MetadataFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -65,29 +65,38 @@ public function setCache(CacheInterface $cache)
public function getMetadataForClass($className)
{
if (isset($this->loadedMetadata[$className])) {
return $this->loadedMetadata[$className];
return $this->filterNullMetadata($this->loadedMetadata[$className]);
}

$metadata = null;
foreach ($this->getClassHierarchy($className) as $class) {
if (isset($this->loadedClassMetadata[$name = $class->getName()])) {
$this->addClassMetadata($metadata, $this->loadedClassMetadata[$name]);
if (null !== $classMetadata = $this->filterNullMetadata($this->loadedClassMetadata[$name])) {
$this->addClassMetadata($metadata, $classMetadata);
}
continue;
}

// check the cache
if (null !== $this->cache && (null !== $classMetadata = $this->cache->loadClassMetadataFromCache($class))) {
if ( ! $classMetadata instanceof ClassMetadata) {
throw new \LogicException(sprintf('The cache must return instances of ClassMetadata, but got %s.', var_export($classMetadata, true)));
}

if ($this->debug && !$classMetadata->isFresh()) {
$this->cache->evictClassMetadataFromCache($classMetadata->reflection);
} else {
if (null !== $this->cache) {
if (($classMetadata = $this->cache->loadClassMetadataFromCache($class)) instanceof NullMetadata) {
$this->loadedClassMetadata[$name] = $classMetadata;
$this->addClassMetadata($metadata, $classMetadata);
continue;
}

if (null !== $classMetadata) {
if ( ! $classMetadata instanceof ClassMetadata) {
throw new \LogicException(sprintf('The cache must return instances of ClassMetadata, but got %s.', var_export($classMetadata, true)));
}

if ($this->debug && !$classMetadata->isFresh()) {
$this->cache->evictClassMetadataFromCache($classMetadata->reflection);
} else {
$this->loadedClassMetadata[$name] = $classMetadata;
$this->addClassMetadata($metadata, $classMetadata);
continue;
}
}
}

// load from source
Expand All @@ -101,9 +110,17 @@ public function getMetadataForClass($className)

continue;
}

if (null !== $this->cache && !$this->debug) {
$this->cache->putClassMetadataInCache(new NullMetadata());
}
}

if (null === $metadata) {
$metadata = new NullMetadata();
}

return $this->loadedMetadata[$className] = $metadata;
return $this->filterNullMetadata($this->loadedMetadata[$className] = $metadata);
}

/**
Expand Down Expand Up @@ -175,4 +192,9 @@ private function getClassHierarchy($class)

return $newHierarchy;
}

private function filterNullMetadata($metadata = null)
{
return !$metadata instanceof NullMetadata ? $metadata : null;
}
}
26 changes: 26 additions & 0 deletions src/Metadata/NullMetadata.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?php

namespace Metadata;

/**
* Represents the metadata for a class that has not metadata.
*
* @author Adrien Brault <[email protected]>
*/
class NullMetadata extends ClassMetadata
{
public function __construct()
{

}

public function serialize()
{
return '';
}

public function unserialize($str)
{

}
}
78 changes: 78 additions & 0 deletions tests/Metadata/Tests/MetadataFactoryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,9 @@ public function testGetMetadataWithCache()
;
$factory->setCache($cache);


$factory->getMetadataForClass('Metadata\Tests\Fixtures\TestObject');
$factory->getMetadataForClass('Metadata\Tests\Fixtures\TestObject');
$this->assertSame($metadata, reset($factory->getMetadataForClass('Metadata\Tests\Fixtures\TestObject')->classMetadata));
}

Expand Down Expand Up @@ -198,4 +201,79 @@ public function testGetAllClassNamesThrowsException()
$factory = new MetadataFactory($this->getMock('Metadata\Driver\DriverInterface'));
$factory->getAllClassNames();
}

public function testNotFoundMetadataIsCached()
{
$driver = $this->getMock('Metadata\Driver\DriverInterface');
$driver
->expects($this->once()) // This is the important part of this test
->method('loadMetadataForClass')
->will($this->returnValue(null))
;

$cachedMetadata = null;
$cache = $this->getMock('Metadata\Cache\CacheInterface');
$cache
->expects($this->any())
->method('loadClassMetadataFromCache')
->with($this->equalTo(new \ReflectionClass('Metadata\Tests\Fixtures\TestObject')))
->will($this->returnCallback(function () use (&$cachedMetadata) {
return $cachedMetadata;
}))
;
$cache
->expects($this->once())
->method('putClassMetadataInCache')
->will($this->returnCallback(function ($metadata) use (&$cachedMetadata) {
$cachedMetadata = $metadata;
}))
;

$factory = new MetadataFactory($driver);
$factory->setCache($cache);
$factory->getMetadataForClass('Metadata\Tests\Fixtures\TestObject');
$factory->getMetadataForClass('Metadata\Tests\Fixtures\TestObject');
$this->assertNull($factory->getMetadataForClass('Metadata\Tests\Fixtures\TestObject'));

// We use another factory with the same cache, to simulate another request and skip the in memory
$factory = new MetadataFactory($driver);
$factory->setCache($cache);
$factory->getMetadataForClass('Metadata\Tests\Fixtures\TestObject');
$factory->getMetadataForClass('Metadata\Tests\Fixtures\TestObject');
$this->assertNull($factory->getMetadataForClass('Metadata\Tests\Fixtures\TestObject'));
}

public function testNotFoundMetadataIsNotCachedInDebug()
{
$driver = $this->getMock('Metadata\Driver\DriverInterface');
$driver
->expects($this->exactly(2))
->method('loadMetadataForClass')
->will($this->returnValue(null))
;

$cachedMetadata = null;
$cache = $this->getMock('Metadata\Cache\CacheInterface');
$cache
->expects($this->any())
->method('loadClassMetadataFromCache')
->with($this->equalTo(new \ReflectionClass('Metadata\Tests\Fixtures\TestObject')))
->will($this->returnValue(null))
;
$cache
->expects($this->never())
->method('putClassMetadataInCache')
;

$factory = new MetadataFactory($driver, 'Metadata\ClassHierarchyMetadata', true);
$factory->setCache($cache);
$factory->getMetadataForClass('Metadata\Tests\Fixtures\TestObject');
$this->assertNull($factory->getMetadataForClass('Metadata\Tests\Fixtures\TestObject'));

// We use another factory with the same cache, to simulate another request and skip the in memory
$factory = new MetadataFactory($driver, 'Metadata\ClassHierarchyMetadata', true);
$factory->setCache($cache);
$factory->getMetadataForClass('Metadata\Tests\Fixtures\TestObject');
$this->assertNull($factory->getMetadataForClass('Metadata\Tests\Fixtures\TestObject'));
}
}

0 comments on commit 32458c4

Please sign in to comment.