[DI][Router][DX] Invalidate routing cache when container parameters changed
This commit is contained in:
parent
e58be70aca
commit
fad4d9e2ef
@ -64,6 +64,11 @@
|
||||
<argument type="collection"></argument>
|
||||
</service>
|
||||
|
||||
<service class="Symfony\Component\DependencyInjection\Config\ContainerParametersResourceChecker" public="false">
|
||||
<argument type="service" id="service_container" />
|
||||
<tag name="config_cache.resource_checker" priority="-980" />
|
||||
</service>
|
||||
|
||||
<service class="Symfony\Component\Config\Resource\SelfCheckingResourceChecker" public="false">
|
||||
<tag name="config_cache.resource_checker" priority="-990" />
|
||||
</service>
|
||||
|
@ -11,6 +11,7 @@
|
||||
|
||||
namespace Symfony\Bundle\FrameworkBundle\Routing;
|
||||
|
||||
use Symfony\Component\DependencyInjection\Config\ContainerParametersResource;
|
||||
use Symfony\Component\Routing\Router as BaseRouter;
|
||||
use Symfony\Component\Routing\RequestContext;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
@ -27,6 +28,7 @@ use Symfony\Component\DependencyInjection\Exception\RuntimeException;
|
||||
class Router extends BaseRouter implements WarmableInterface
|
||||
{
|
||||
private $container;
|
||||
private $collectedParameters = array();
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
@ -53,6 +55,7 @@ class Router extends BaseRouter implements WarmableInterface
|
||||
if (null === $this->collection) {
|
||||
$this->collection = $this->container->get('routing.loader')->load($this->resource, $this->options['resource_type']);
|
||||
$this->resolveParameters($this->collection);
|
||||
$this->collection->addResource(new ContainerParametersResource($this->collectedParameters));
|
||||
}
|
||||
|
||||
return $this->collection;
|
||||
@ -153,6 +156,8 @@ class Router extends BaseRouter implements WarmableInterface
|
||||
$resolved = $container->getParameter($match[1]);
|
||||
|
||||
if (is_string($resolved) || is_numeric($resolved)) {
|
||||
$this->collectedParameters[$match[1]] = $resolved;
|
||||
|
||||
return (string) $resolved;
|
||||
}
|
||||
|
||||
|
@ -13,6 +13,7 @@ namespace Symfony\Bundle\FrameworkBundle\Tests\Routing;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Bundle\FrameworkBundle\Routing\Router;
|
||||
use Symfony\Component\DependencyInjection\Config\ContainerParametersResource;
|
||||
use Symfony\Component\Routing\Route;
|
||||
use Symfony\Component\Routing\RouteCollection;
|
||||
|
||||
@ -217,6 +218,20 @@ class RouterTest extends TestCase
|
||||
$this->assertSame($value, $route->getDefault('foo'));
|
||||
}
|
||||
|
||||
public function testGetRouteCollectionAddsContainerParametersResource()
|
||||
{
|
||||
$routeCollection = $this->getMockBuilder(RouteCollection::class)->getMock();
|
||||
$routeCollection->method('getIterator')->willReturn(new \ArrayIterator(array(new Route('/%locale%'))));
|
||||
$routeCollection->expects($this->once())->method('addResource')->with(new ContainerParametersResource(array('locale' => 'en')));
|
||||
|
||||
$sc = $this->getServiceContainer($routeCollection);
|
||||
$sc->setParameter('locale', 'en');
|
||||
|
||||
$router = new Router($sc, 'foo');
|
||||
|
||||
$router->getRouteCollection();
|
||||
}
|
||||
|
||||
public function getNonStringValues()
|
||||
{
|
||||
return array(array(null), array(false), array(true), array(new \stdClass()), array(array('foo', 'bar')), array(array(array())));
|
||||
|
@ -0,0 +1,64 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\DependencyInjection\Config;
|
||||
|
||||
use Symfony\Component\Config\Resource\ResourceInterface;
|
||||
|
||||
/**
|
||||
* Tracks container parameters.
|
||||
*
|
||||
* @author Maxime Steinhausser <maxime.steinhausser@gmail.com>
|
||||
*/
|
||||
class ContainerParametersResource implements ResourceInterface, \Serializable
|
||||
{
|
||||
private $parameters;
|
||||
|
||||
/**
|
||||
* @param array $parameters The container parameters to track
|
||||
*/
|
||||
public function __construct(array $parameters)
|
||||
{
|
||||
$this->parameters = $parameters;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return 'container_parameters_'.md5(serialize($this->parameters));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function serialize()
|
||||
{
|
||||
return serialize($this->parameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function unserialize($serialized)
|
||||
{
|
||||
$this->parameters = unserialize($serialized);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array Tracked parameters
|
||||
*/
|
||||
public function getParameters()
|
||||
{
|
||||
return $this->parameters;
|
||||
}
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\DependencyInjection\Config;
|
||||
|
||||
use Symfony\Component\Config\Resource\ResourceInterface;
|
||||
use Symfony\Component\Config\ResourceCheckerInterface;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
/**
|
||||
* @author Maxime Steinhausser <maxime.steinhausser@gmail.com>
|
||||
*/
|
||||
class ContainerParametersResourceChecker implements ResourceCheckerInterface
|
||||
{
|
||||
/** @var ContainerInterface */
|
||||
private $container;
|
||||
|
||||
public function __construct(ContainerInterface $container)
|
||||
{
|
||||
$this->container = $container;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function supports(ResourceInterface $metadata)
|
||||
{
|
||||
return $metadata instanceof ContainerParametersResource;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isFresh(ResourceInterface $resource, $timestamp)
|
||||
{
|
||||
foreach ($resource->getParameters() as $key => $value) {
|
||||
if (!$this->container->hasParameter($key) || $this->container->getParameter($key) !== $value) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
@ -0,0 +1,77 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\DependencyInjection\Tests\Config;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\Config\ResourceCheckerInterface;
|
||||
use Symfony\Component\DependencyInjection\Config\ContainerParametersResource;
|
||||
use Symfony\Component\DependencyInjection\Config\ContainerParametersResourceChecker;
|
||||
use Symfony\Component\DependencyInjection\ContainerInterface;
|
||||
|
||||
class ContainerParametersResourceCheckerTest extends TestCase
|
||||
{
|
||||
/** @var ContainerParametersResource */
|
||||
private $resource;
|
||||
|
||||
/** @var ResourceCheckerInterface */
|
||||
private $resourceChecker;
|
||||
|
||||
/** @var ContainerInterface */
|
||||
private $container;
|
||||
|
||||
protected function setUp()
|
||||
{
|
||||
$this->resource = new ContainerParametersResource(array('locales' => array('fr', 'en'), 'default_locale' => 'fr'));
|
||||
$this->container = $this->getMockBuilder(ContainerInterface::class)->getMock();
|
||||
$this->resourceChecker = new ContainerParametersResourceChecker($this->container);
|
||||
}
|
||||
|
||||
public function testSupports()
|
||||
{
|
||||
$this->assertTrue($this->resourceChecker->supports($this->resource));
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider isFreshProvider
|
||||
*/
|
||||
public function testIsFresh(callable $mockContainer, $expected)
|
||||
{
|
||||
$mockContainer($this->container);
|
||||
|
||||
$this->assertSame($expected, $this->resourceChecker->isFresh($this->resource, time()));
|
||||
}
|
||||
|
||||
public function isFreshProvider()
|
||||
{
|
||||
yield 'not fresh on missing parameter' => array(function (\PHPUnit_Framework_MockObject_MockObject $container) {
|
||||
$container->method('hasParameter')->with('locales')->willReturn(false);
|
||||
}, false);
|
||||
|
||||
yield 'not fresh on different value' => array(function (\PHPUnit_Framework_MockObject_MockObject $container) {
|
||||
$container->method('getParameter')->with('locales')->willReturn(array('nl', 'es'));
|
||||
}, false);
|
||||
|
||||
yield 'fresh on every identical parameters' => array(function (\PHPUnit_Framework_MockObject_MockObject $container) {
|
||||
$container->expects($this->exactly(2))->method('hasParameter')->willReturn(true);
|
||||
$container->expects($this->exactly(2))->method('getParameter')
|
||||
->withConsecutive(
|
||||
array($this->equalTo('locales')),
|
||||
array($this->equalTo('default_locale'))
|
||||
)
|
||||
->will($this->returnValueMap(array(
|
||||
array('locales', array('fr', 'en')),
|
||||
array('default_locale', 'fr'),
|
||||
)))
|
||||
;
|
||||
}, true);
|
||||
}
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Symfony\Component\DependencyInjection\Tests\Config;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\DependencyInjection\Config\ContainerParametersResource;
|
||||
|
||||
class ContainerParametersResourceTest extends TestCase
|
||||
{
|
||||
/** @var ContainerParametersResource */
|
||||
private $resource;
|
||||
|
||||
protected function setUp()
|
||||
{
|
||||
$this->resource = new ContainerParametersResource(array('locales' => array('fr', 'en'), 'default_locale' => 'fr'));
|
||||
}
|
||||
|
||||
public function testToString()
|
||||
{
|
||||
$this->assertSame('container_parameters_9893d3133814ab03cac3490f36dece77', (string) $this->resource);
|
||||
}
|
||||
|
||||
public function testSerializeUnserialize()
|
||||
{
|
||||
$unserialized = unserialize(serialize($this->resource));
|
||||
|
||||
$this->assertEquals($this->resource, $unserialized);
|
||||
}
|
||||
|
||||
public function testGetParameters()
|
||||
{
|
||||
$this->assertSame(array('locales' => array('fr', 'en'), 'default_locale' => 'fr'), $this->resource->getParameters());
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user