From b49fa129bdb3c0aa970a006b16dd1ca63a9d7ebd Mon Sep 17 00:00:00 2001 From: thewilkybarkid Date: Sat, 13 Dec 2014 16:43:22 +0000 Subject: [PATCH] Make the container considered non-fresh if the environment parameters are changed --- .../Config/EnvParametersResource.php | 95 ++++++++++++++++ src/Symfony/Component/HttpKernel/Kernel.php | 2 + .../Config/EnvParametersResourceTest.php | 106 ++++++++++++++++++ .../Component/HttpKernel/Tests/KernelTest.php | 30 +++++ 4 files changed, 233 insertions(+) create mode 100644 src/Symfony/Component/HttpKernel/Config/EnvParametersResource.php create mode 100644 src/Symfony/Component/HttpKernel/Tests/Config/EnvParametersResourceTest.php diff --git a/src/Symfony/Component/HttpKernel/Config/EnvParametersResource.php b/src/Symfony/Component/HttpKernel/Config/EnvParametersResource.php new file mode 100644 index 0000000000..5f54450137 --- /dev/null +++ b/src/Symfony/Component/HttpKernel/Config/EnvParametersResource.php @@ -0,0 +1,95 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpKernel\Config; + +use Symfony\Component\Config\Resource\ResourceInterface; + +/** + * EnvParametersResource represents resources stored in prefixed environment variables. + * + * @author Chris Wilkinson + */ +class EnvParametersResource implements ResourceInterface, \Serializable +{ + /** + * @var string + */ + private $prefix; + + /** + * @var string + */ + private $variables; + + /** + * Constructor. + * + * @param string $prefix + */ + public function __construct($prefix) + { + $this->prefix = $prefix; + $this->variables = $this->findVariables(); + } + + /** + * {@inheritdoc} + */ + public function __toString() + { + return serialize($this->getResource()); + } + + /** + * {@inheritdoc} + */ + public function getResource() + { + return array('prefix' => $this->prefix, 'variables' => $this->variables); + } + + /** + * {@inheritdoc} + */ + public function isFresh($timestamp) + { + return $this->findVariables() === $this->variables; + } + + public function serialize() + { + return serialize(array('prefix' => $this->prefix, 'variables' => $this->variables)); + } + + public function unserialize($serialized) + { + $unserialized = unserialize($serialized); + + $this->prefix = $unserialized['prefix']; + $this->variables = $unserialized['variables']; + } + + private function findVariables() + { + $variables = array(); + + foreach ($_SERVER as $key => $value) { + if (0 === strpos($key, $this->prefix)) { + $variables[$key] = $value; + } + } + + ksort($variables); + + return $variables; + } +} diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index a0e6b1a860..968f2a1599 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -25,6 +25,7 @@ use Symfony\Component\DependencyInjection\Loader\ClosureLoader; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Bundle\BundleInterface; +use Symfony\Component\HttpKernel\Config\EnvParametersResource; use Symfony\Component\HttpKernel\Config\FileLocator; use Symfony\Component\HttpKernel\DependencyInjection\MergeExtensionConfigurationPass; use Symfony\Component\HttpKernel\DependencyInjection\AddClassesToCachePass; @@ -647,6 +648,7 @@ abstract class Kernel implements KernelInterface, TerminableInterface } $container->addCompilerPass(new AddClassesToCachePass($this)); + $container->addResource(new EnvParametersResource('SYMFONY__')); return $container; } diff --git a/src/Symfony/Component/HttpKernel/Tests/Config/EnvParametersResourceTest.php b/src/Symfony/Component/HttpKernel/Tests/Config/EnvParametersResourceTest.php new file mode 100644 index 0000000000..ee5ecce3ce --- /dev/null +++ b/src/Symfony/Component/HttpKernel/Tests/Config/EnvParametersResourceTest.php @@ -0,0 +1,106 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpKernel\Tests\Config; + +use Symfony\Component\HttpKernel\Config\EnvParametersResource; + +class EnvParametersResourceTest extends \PHPUnit_Framework_TestCase +{ + protected $prefix = '__DUMMY_'; + protected $initialEnv; + protected $resource; + + protected function setUp() + { + $this->initialEnv = array( + $this->prefix.'1' => 'foo', + $this->prefix.'2' => 'bar', + ); + + foreach ($this->initialEnv as $key => $value) { + $_SERVER[$key] = $value; + } + + $this->resource = new EnvParametersResource($this->prefix); + } + + protected function tearDown() + { + foreach ($_SERVER as $key => $value) { + if (0 === strpos($key, $this->prefix)) { + unset($_SERVER[$key]); + } + } + } + + public function testGetResource() + { + $this->assertSame( + array('prefix' => $this->prefix, 'variables' => $this->initialEnv), + $this->resource->getResource(), + '->getResource() returns the resource' + ); + } + + public function testToString() + { + $this->assertSame( + serialize(array('prefix' => $this->prefix, 'variables' => $this->initialEnv)), + (string) $this->resource + ); + } + + public function testIsFreshNotChanged() + { + $this->assertTrue( + $this->resource->isFresh(time()), + '->isFresh() returns true if the variables have not changed' + ); + } + + public function testIsFreshValueChanged() + { + reset($this->initialEnv); + $_SERVER[key($this->initialEnv)] = 'baz'; + + $this->assertFalse( + $this->resource->isFresh(time()), + '->isFresh() returns false if a variable has been changed' + ); + } + + public function testIsFreshValueRemoved() + { + reset($this->initialEnv); + unset($_SERVER[key($this->initialEnv)]); + + $this->assertFalse( + $this->resource->isFresh(time()), + '->isFresh() returns false if a variable has been removed' + ); + } + + public function testIsFreshValueAdded() + { + $_SERVER[$this->prefix.'3'] = 'foo'; + + $this->assertFalse( + $this->resource->isFresh(time()), + '->isFresh() returns false if a variable has been added' + ); + } + + public function testSerializeUnserialize() + { + $this->assertEquals($this->resource, unserialize(serialize($this->resource))); + } +} diff --git a/src/Symfony/Component/HttpKernel/Tests/KernelTest.php b/src/Symfony/Component/HttpKernel/Tests/KernelTest.php index b68e37e398..468d30cec8 100644 --- a/src/Symfony/Component/HttpKernel/Tests/KernelTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/KernelTest.php @@ -11,6 +11,7 @@ namespace Symfony\Component\HttpKernel\Tests; +use Symfony\Component\HttpKernel\Config\EnvParametersResource; use Symfony\Component\HttpKernel\Kernel; use Symfony\Component\HttpKernel\Bundle\Bundle; use Symfony\Component\HttpKernel\HttpKernelInterface; @@ -154,6 +155,35 @@ class KernelTest extends \PHPUnit_Framework_TestCase ->method('doLoadClassCache'); } + public function testEnvParametersResourceIsAdded() + { + $container = $this->getMock('Symfony\Component\DependencyInjection\ContainerBuilder'); + $kernel = $this->getMockBuilder('Symfony\Component\HttpKernel\Tests\Fixtures\KernelForTest') + ->disableOriginalConstructor() + ->setMethods(array('getContainerBuilder', 'prepareContainer', 'getCacheDir', 'getLogDir')) + ->getMock(); + $kernel->expects($this->any()) + ->method('getContainerBuilder') + ->will($this->returnValue($container)); + $kernel->expects($this->any()) + ->method('prepareContainer') + ->will($this->returnValue(null)); + $kernel->expects($this->any()) + ->method('getCacheDir') + ->will($this->returnValue(sys_get_temp_dir())); + $kernel->expects($this->any()) + ->method('getLogDir') + ->will($this->returnValue(sys_get_temp_dir())); + $container->expects($this->once()) + ->method('addResource') + ->with(new EnvParametersResource('SYMFONY__')); + + $reflection = new \ReflectionClass(get_class($kernel)); + $method = $reflection->getMethod('buildContainer'); + $method->setAccessible(true); + $method->invoke($kernel); + } + public function testBootKernelSeveralTimesOnlyInitializesBundlesOnce() { $kernel = $this->getMockBuilder('Symfony\Component\HttpKernel\Tests\Fixtures\KernelForTest')