Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit df536ca

Browse filesBrowse files
committed
WIP Smart caching system to only clear container cache when it's *actually* needed
1 parent b868feb commit df536ca
Copy full SHA for df536ca

File tree

Expand file treeCollapse file tree

6 files changed

+336
-1
lines changed
Filter options
Expand file treeCollapse file tree

6 files changed

+336
-1
lines changed

‎src/Symfony/Bundle/FrameworkBundle/Resources/config/services.xml

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/FrameworkBundle/Resources/config/services.xml
+4Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,5 +54,9 @@
5454
<tag name="config_cache.resource_checker" priority="-990" />
5555
</service>
5656

57+
<service class="Symfony\Component\DependencyInjection\Config\AutowireResourceChecker" public="false">
58+
<tag name="config_cache.resource_checker" />
59+
</service>
60+
5761
</services>
5862
</container>

‎src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php
+28-1Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
namespace Symfony\Component\DependencyInjection\Compiler;
1313

14+
use Symfony\Component\DependencyInjection\Config\AutowireServiceResource;
1415
use Symfony\Component\DependencyInjection\ContainerBuilder;
1516
use Symfony\Component\DependencyInjection\Definition;
1617
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
@@ -23,6 +24,9 @@
2324
*/
2425
class AutowirePass implements CompilerPassInterface
2526
{
27+
/**
28+
* @var ContainerBuilder
29+
*/
2630
private $container;
2731
private $reflectionClasses = array();
2832
private $definedTypes = array();
@@ -49,6 +53,29 @@ public function process(ContainerBuilder $container)
4953
$this->ambiguousServiceTypes = array();
5054
}
5155

56+
/**
57+
* Creates a resource to help know if this service has changed.
58+
*
59+
* @param \ReflectionClass $reflectionClass
60+
*
61+
* @return AutowireServiceResource
62+
*/
63+
public function createResourceForClass(\ReflectionClass $reflectionClass)
64+
{
65+
$constructor = $reflectionClass->getConstructor();
66+
$constructorParams = $constructor ? $constructor->getParameters() : array();
67+
$constructorArgumentsForResource = array();
68+
foreach ($constructorParams as $parameter) {
69+
$constructorArgumentsForResource[] = $parameter->getClass();
70+
}
71+
72+
return new AutowireServiceResource(
73+
$reflectionClass->name,
74+
$reflectionClass->getFileName(),
75+
$constructorArgumentsForResource
76+
);
77+
}
78+
5279
/**
5380
* Wires the given definition.
5481
*
@@ -63,7 +90,7 @@ private function completeDefinition($id, Definition $definition)
6390
return;
6491
}
6592

66-
$this->container->addClassResource($reflectionClass);
93+
$this->container->addResource($this->createResourceForClass($reflectionClass));
6794

6895
if (!$constructor = $reflectionClass->getConstructor()) {
6996
return;
+51Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\DependencyInjection\Config;
13+
14+
use Symfony\Component\Config\Resource\ResourceInterface;
15+
use Symfony\Component\Config\ResourceCheckerInterface;
16+
use Symfony\Component\DependencyInjection\Compiler\AutowirePass;
17+
18+
class AutowireResourceChecker implements ResourceCheckerInterface
19+
{
20+
private $autowirePass;
21+
22+
public function supports(ResourceInterface $metadata)
23+
{
24+
return $metadata instanceof AutowireServiceResource;
25+
}
26+
27+
public function isFresh(ResourceInterface $resource, $timestamp)
28+
{
29+
/* @var AutowireServiceResource $resource */
30+
$path = $resource->getFilePath();
31+
32+
if (!file_exists($path)) {
33+
return false;
34+
}
35+
36+
// has the file *not* been modified? Definitely fresh
37+
if (@filemtime($path) <= $timestamp) {
38+
return true;
39+
}
40+
41+
$pass = $this->autowirePass ? $this->autowirePass : new AutowirePass();
42+
$newResource = $pass->createResourceForClass(new \ReflectionClass($resource->getClass()));
43+
44+
return $newResource == $resource;
45+
}
46+
47+
public function setAutowirePass(AutowirePass $autowirePass)
48+
{
49+
$this->autowirePass = $autowirePass;
50+
}
51+
}
+75Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\DependencyInjection\Config;
13+
14+
use Symfony\Component\Config\Resource\ResourceInterface;
15+
16+
class AutowireServiceResource implements ResourceInterface, \Serializable
17+
{
18+
private $class;
19+
private $filePath;
20+
private $constructorArguments;
21+
22+
public function __construct($class, $path)
23+
{
24+
$this->class = $class;
25+
$this->filePath = $path;
26+
}
27+
28+
/**
29+
* An array of arguments: 0 => type-hinted class (or null of there is no type-hint).
30+
*
31+
* @param array $constructorArguments
32+
*/
33+
public function setConstructorArguments(array $constructorArguments)
34+
{
35+
$this->constructorArguments = $constructorArguments;
36+
}
37+
38+
public function getFilePath()
39+
{
40+
return $this->filePath;
41+
}
42+
43+
public function getClass()
44+
{
45+
return $this->class;
46+
}
47+
48+
public function __toString()
49+
{
50+
return 'service.autowire.'.$this->class;
51+
}
52+
53+
public function serialize()
54+
{
55+
return serialize(array(
56+
$this->class,
57+
$this->filePath,
58+
$this->constructorArguments,
59+
));
60+
}
61+
62+
public function unserialize($serialized)
63+
{
64+
list(
65+
$this->class,
66+
$this->filePath,
67+
$this->constructorArguments
68+
) = unserialize($serialized);
69+
}
70+
71+
// class name
72+
// file name (to see if it's even been modified?)
73+
// construct arguments + classes
74+
// all setters with arguments + classes
75+
}
+118Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\DependencyInjection\Tests\Config;
13+
14+
use Symfony\Component\DependencyInjection\Config\AutowireResourceChecker;
15+
use Symfony\Component\DependencyInjection\Config\AutowireServiceResource;
16+
17+
class AutowireResourceCheckerTest extends \PHPUnit_Framework_TestCase
18+
{
19+
/**
20+
* @var AutowireServiceResource
21+
*/
22+
private $resource;
23+
private $file;
24+
private $class;
25+
private $time;
26+
private $constructorArgs;
27+
28+
protected function setUp()
29+
{
30+
$this->file = realpath(sys_get_temp_dir()).'/tmp.php';
31+
$this->time = time();
32+
touch($this->file, $this->time);
33+
34+
$this->class = __NAMESPACE__.'\FooReplicator';
35+
$this->resource = new AutowireServiceResource(
36+
$this->class,
37+
$this->file
38+
);
39+
$this->constructorArgs = array(
40+
null, // no type-hint on this argument
41+
'AppBundle\Entity\Foo',
42+
);
43+
$this->resource->setConstructorArguments($this->constructorArgs);
44+
}
45+
46+
protected function tearDown()
47+
{
48+
if (!file_exists($this->file)) {
49+
return;
50+
}
51+
52+
unlink($this->file);
53+
}
54+
55+
public function testIsFresh()
56+
{
57+
$checker = new AutowireResourceChecker();
58+
59+
$this->assertTrue($checker->isFresh($this->resource, $this->time), '->isFresh() returns true if the resource has not changed in same second');
60+
$this->assertTrue($checker->isFresh($this->resource, $this->time + 10), '->isFresh() returns true if the resource has not changed');
61+
$this->assertFalse($checker->isFresh($this->resource, $this->time - 86400), '->isFresh() returns false if the resource has been updated');
62+
}
63+
64+
public function testIsFreshForDeletedResources()
65+
{
66+
unlink($this->file);
67+
68+
$checker = new AutowireResourceChecker();
69+
$this->assertFalse($checker->isFresh($this->resource, $this->time), '->isFresh() returns false if the resource does not exist');
70+
}
71+
72+
public function testIsFreshChangedConstructorArgs()
73+
{
74+
$newResource = new AutowireServiceResource(
75+
$this->class,
76+
$this->file
77+
);
78+
// a new 3rd argument was added!
79+
$args = $this->constructorArgs;
80+
$args[] = 'AppBundle\Entity\Bar';
81+
$newResource->setConstructorArguments($args);
82+
83+
// mock so that this is returned as the "new" resource
84+
$autowirePass = $this->getMock('Symfony\Component\DependencyInjection\Compiler\AutowirePass');
85+
$autowirePass->expects($this->once())
86+
->method('createResourceForClass')
87+
->will($this->returnValue($newResource));
88+
89+
$checker = new AutowireResourceChecker();
90+
$checker->setAutowirePass($autowirePass);
91+
$this->assertFalse($checker->isFresh($this->resource, $this->time - 10), '->isFresh() returns false if the constructor arguments have changed');
92+
}
93+
94+
public function testIsFreshSameConstructorArgs()
95+
{
96+
$newResource = new AutowireServiceResource(
97+
$this->class,
98+
$this->file
99+
);
100+
101+
$newResource->setConstructorArguments($this->constructorArgs);
102+
103+
// mock so that this is returned as the "new" resource
104+
$autowirePass = $this->getMock('Symfony\Component\DependencyInjection\Compiler\AutowirePass');
105+
$autowirePass->expects($this->once())
106+
->method('createResourceForClass')
107+
->will($this->returnValue($newResource));
108+
109+
$checker = new AutowireResourceChecker();
110+
$checker->setAutowirePass($autowirePass);
111+
$this->assertFalse($checker->isFresh($this->resource, $this->time - 10), '->isFresh() returns false if the constructor arguments have changed');
112+
}
113+
}
114+
115+
// exists just so that some reflection in the tests doesn't fail
116+
class FooReplicator
117+
{
118+
}
+60Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\DependencyInjection\Tests\Config;
13+
14+
use Symfony\Component\DependencyInjection\Config\AutowireServiceResource;
15+
16+
class AutowireServiceResourceTest extends \PHPUnit_Framework_TestCase
17+
{
18+
/**
19+
* @var AutowireServiceResource
20+
*/
21+
private $resource;
22+
private $file;
23+
private $class;
24+
25+
protected function setUp()
26+
{
27+
$this->file = '/tmp/foo';
28+
$this->class = 'AppBundle\Service\FooReplicator';
29+
$this->resource = new AutowireServiceResource(
30+
$this->class,
31+
$this->file
32+
);
33+
$this->resource->setConstructorArguments(array(
34+
null, // no type-hint on this argument
35+
'AppBundle\Entity\Foo',
36+
));
37+
}
38+
39+
public function testGetFilePath()
40+
{
41+
$this->assertSame($this->file, $this->resource->getFilePath());
42+
}
43+
44+
public function testGetClass()
45+
{
46+
$this->assertSame($this->class, $this->resource->getClass());
47+
}
48+
49+
public function testToString()
50+
{
51+
$this->assertSame('service.autowire.'.$this->class, (string) $this->resource);
52+
}
53+
54+
public function testSerializeUnserialize()
55+
{
56+
$unserialized = unserialize(serialize($this->resource));
57+
58+
$this->assertEquals($this->resource, $unserialized);
59+
}
60+
}

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.