Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,8 @@
"email": "[email protected]"
}
],
"minimum-stability": "stable",
"require": {
"ezsystems/ezpublish-kernel": "^6.7@dev || ^7.0@dev",
"ezsystems/ezpublish-kernel": "~6.7.7@dev || ^6.12.1@dev || ^7.0@dev",
"friendsofsymfony/http-cache-bundle": "~1.2|^1.3.8",
"symfony/symfony": "^2.7 | ^3.1"
},
Expand All @@ -33,7 +32,7 @@
},
"extra": {
"branch-alias": {
"dev-master": "0.1.x-dev"
"dev-master": "0.3.x-dev"
}
}
}
66 changes: 66 additions & 0 deletions docs/drivers.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# Driver support

You may add integration with other http caches using the extension points provided by this bundle.

The following extension points are available
- PurgeClient
- TagHandler
- FOS TagHandler

If you write a new PurgeClient driver, you **must** also create a corresponding TagHandler and vice
versa. Creating a FOS TagHandler is optional.


## PurgeClient

The PurgeClient is responsible for sending purge requests to the http cache when content is about to be invalidated.
The PurgeClient must implement EzSystems\PlatformHttpCacheBundle\PurgeClient\PurgeClientInterface and can be registered
with the following code in services.yml:

```
services:
ezplatform.http_cache_myhttpcachebundle.purge_client.myhttpcache:
class: EzSystems\PlatformMyHttpCacheBundle\PurgeClient\MyHttpCachePurgeClient
arguments: ['@ezplatform.http_cache.cache_manager']
tags:
- {name: ezplatform.http_cache.purge_client, purge_type: myhttpcache}
```

Any service which implements the PurgeClientInterface must be tagged with `ezplatform.http_cache.purge_client` in order
to be registered as such.
`purge_type` specifies what the value of the purge_type setting in `app/config/ezplatform.yml` should be in order to
enable this driver.


## TagHandler

The TagHandler is responsible for tagging responses with headers which the http cache recognizes.
The TagHandler must implement EzSystems\PlatformHttpCacheBundle\Handler\TagHandlerInterface and can be registered with
the following code in services.yml:

```
ezplatform.http_cache_myhttpcachebundle.tag_handler.myhttpcache:
class: EzSystems\PlatformMyHttpCacheBundle\Handler\MyHttpCacheTagHandler
tags:
- {name: ezplatform.http_cache.tag_handler, purge_type: myhttpcache}

```

Any service which implements the TagHandlerInterface must be tagged with `ezplatform.http_cache.tag_handler` in order
to be registered as such.

## FOS TagHandler

The FOS Http cache bundle also has a TagHandler which is not used by eZ Platform except for one thing, the
`fos:httpcache:invalidate:tag` command. With this command you may explicitly invalidate cache by tag.

Normally, you would not need to implement your own FOS TagHandler as the ezplatform-http-cache bundle ships with a
default one which uses the PurgeClient to invalidate the given tags.
If you need to write your own FOS TagHandler anyway, you may register it with the following code in services.yml:

```
ezplatform.http_cache_myhttpcachebundle.fos_tag_handler.myhttpcache:
class: EzSystems\PlatformMyHttpCacheBundle\Handler\MyHttpCacheFosTagHandler
tags:
- {name: ezplatform.http_cache.fos_tag_handler, purge_type: myhttpcache}
```
2 changes: 0 additions & 2 deletions spec/DependencyInjection/Compiler/KernelPassSpec.php
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,6 @@ function it_disables_the_kernels_httpcache_services(ContainerBuilder $container,
]
])->shouldBeCalled();

$container->getParameter('purge_type')->shouldBeCalled();

$this->process($container);
}
}
72 changes: 72 additions & 0 deletions src/DependencyInjection/Compiler/DriverPass.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
<?php

namespace EzSystems\PlatformHttpCacheBundle\DependencyInjection\Compiler;

use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;

/**
* We support http cache drivers to be provided by 3rd party bundles.
* This pass loads those drivers as documented in doc/drivers.md.
*/
class DriverPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container)
{
$container->removeAlias('ezpublish.http_cache.purge_client');

$purgeType = $container->getParameter('ezpublish.http_cache.purge_type');
$configuredPurgeClientServiceId = static::getTaggedService($container, 'ezplatform.http_cache.purge_client');
if ($configuredPurgeClientServiceId === null) {
throw new \InvalidArgumentException("No driver found being able to handle purge_type '$purgeType'.");
}
$container->setAlias('ezplatform.http_cache.purge_client', $configuredPurgeClientServiceId);

// TagHandler is responsible for setting correct tags (recognized by the http cache) on responses
$configuredTagHandlerServiceId = static::getTaggedService($container, 'ezplatform.http_cache.tag_handler');
if ($configuredTagHandlerServiceId !== null) {
$container->setAlias('ezplatform.http_cache.tag_handler', $configuredTagHandlerServiceId);
}

// FOS TagHandler is making sure running "php app/console fos:httpcache:invalidate:tag <tag>" works
$configuredFosTagHandlerServiceId = static::getTaggedService($container, 'ezplatform.http_cache.fos_tag_handler');
if ($configuredFosTagHandlerServiceId === null) {
// We default to xkey handler. This one should anyway work for most drivers as it just passes a purge request
// on to the purge client
$configuredFosTagHandlerServiceId = 'ezplatform.http_cache.tag_handler.xkey';
}
$fosTagHandlerDefinition = $container->getDefinition($configuredFosTagHandlerServiceId);
$definition = $container->getDefinition('fos_http_cache.handler.tag_handler');
$definition->setClass($fosTagHandlerDefinition->getClass());
$definition->addArgument(new Reference('ezplatform.http_cache.purge_client'));
}

public static function getTaggedService(ContainerBuilder $container, $tag)
{
$purgeType = $container->getParameter('ezpublish.http_cache.purge_type');
$configuredTagHandlerServiceId = null;

$tagHandlerServiceIds = $container->findTaggedServiceIds($tag);
foreach ($tagHandlerServiceIds as $tagHandlerServiceId => $attributes) {
$currentPurgeTypeId = null;
$currentTagHandlerServiceId = null;
foreach ($attributes as $attribute) {
if (array_key_exists('purge_type', $attribute)) {
$currentPurgeTypeId = $attribute['purge_type'];
}
if ($currentPurgeTypeId !== null) {
if ($purgeType === $attribute['purge_type']) {
$configuredTagHandlerServiceId = $tagHandlerServiceId;
break 2;
}
}
}
if ($currentPurgeTypeId === null) {
throw new \InvalidArgumentException("Missing attribute 'purge_type' in tagged service '$tagHandlerServiceId'.");
}
}

return $configuredTagHandlerServiceId;
}
}
14 changes: 0 additions & 14 deletions src/DependencyInjection/Compiler/KernelPass.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@

use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;
use EzSystems\PlatformHttpCacheBundle\Handler\TagHandler;

/**
* Disables some of the http-cache services declared by the kernel so that
Expand Down Expand Up @@ -43,18 +41,6 @@ public function process(ContainerBuilder $container)
return true;
}));
$container->getDefinition('cache_clearer')->setArguments($arguments);

if ($container->getAlias('ezpublish.http_cache.purge_client') == 'ezpublish.http_cache.purge_client.fos') {
$container->setAlias('ezplatform.http_cache.purge_client', 'ezplatform.http_cache.purge_client.fos');
}

$purgeType = $container->getParameter('purge_type');
if ($purgeType === 'http') {
// Injecting our own Tag handler
$definition = $container->getDefinition('fos_http_cache.handler.tag_handler');
$definition->setClass(TagHandler::class);
$definition->addArgument(new Reference('ezplatform.http_cache.purge_client.fos'));
}
}

/**
Expand Down
2 changes: 1 addition & 1 deletion src/DependencyInjection/Configuration.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ class Configuration implements ConfigurationInterface
public function getConfigTreeBuilder()
{
$treeBuilder = new TreeBuilder();
$rootNode = $treeBuilder->root('ez_systems_platform_http_cache');
$rootNode = $treeBuilder->root('ez_platform_http_cache');

// Here you should define the parameters that are allowed to
// configure your bundle. See the documentation linked above for
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
use Symfony\Component\DependencyInjection\Loader;
use Symfony\Component\Yaml\Yaml;

class EzSystemsPlatformHttpCacheExtension extends Extension implements PrependExtensionInterface
class EzPlatformHttpCacheExtension extends Extension implements PrependExtensionInterface
{
public function load(array $configs, ContainerBuilder $container)
{
Expand Down
8 changes: 8 additions & 0 deletions src/EzSystemsPlatformHttpCacheBundle.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@

use EzSystems\PlatformHttpCacheBundle\DependencyInjection\Compiler\ResponseTaggersPass;
use EzSystems\PlatformHttpCacheBundle\DependencyInjection\Compiler\KernelPass;
use EzSystems\PlatformHttpCacheBundle\DependencyInjection\Compiler\DriverPass;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\HttpKernel\Bundle\Bundle;
use EzSystems\PlatformHttpCacheBundle\DependencyInjection\EzPlatformHttpCacheExtension;

class EzSystemsPlatformHttpCacheBundle extends Bundle
{
Expand All @@ -15,5 +17,11 @@ public function build(ContainerBuilder $container)

$container->addCompilerPass(new ResponseTaggersPass());
$container->addCompilerPass(new KernelPass());
$container->addCompilerPass(new DriverPass());
}

public function getContainerExtension()
{
return new EzPlatformHttpCacheExtension();
}
}
13 changes: 9 additions & 4 deletions src/PurgeClient/PurgeClientInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,16 @@
interface PurgeClientInterface extends KernelPurgeClientInterface
{
/**
* Triggers the cache purge $locationIds.
* Triggers the cache purge of $tags.
*
* It's up to the implementor to decide whether to purge $locationIds right away or to delegate to a separate process.
* It's up to the implementor to decide whether to purge tags right away or to delegate to a separate process.
*
* @param array $locationIds Cache resource(s) to purge (e.g. array of URI to purge in a reverse proxy)
* @param array $tags Array of tags to purge
*/
public function purge($locationIds);
public function purge($tags);

/**
* Purge the whole http cache.
*/
public function purgeAll();
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,8 @@

/**
* Purge client based on FOSHttpCacheBundle.
*
* Only support BAN requests on purpose, to be able to invalidate cache for a
* collection of Location/Content objects.
*/
class FOSPurgeClient implements PurgeClientInterface
class VarnishPurgeClient implements PurgeClientInterface
{
/**
* @var \FOS\HttpCacheBundle\CacheManager
Expand Down
20 changes: 14 additions & 6 deletions src/Resources/config/services.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,27 +5,35 @@ services:

ezplatform.http_cache.proxy_client.varnish.factory:
class: EzSystems\PlatformHttpCacheBundle\PurgeClient\VarnishProxyClientFactory
arguments: ["@ezpublish.config.resolver", "@ezpublish.config.dynamic_setting.parser", "%fos_http_cache.proxy_client.varnish.class%"]
arguments: ['@ezpublish.config.resolver', '@ezpublish.config.dynamic_setting.parser', '%fos_http_cache.proxy_client.varnish.class%']

ezplatform.http_cache.purge_client:
alias: ezplatform.http_cache.purge_client.local

ezplatform.http_cache.purge_client.fos:
class: EzSystems\PlatformHttpCacheBundle\PurgeClient\FOSPurgeClient
arguments: ["@ezplatform.http_cache.cache_manager"]
ezplatform.http_cache.purge_client.varnish:
class: EzSystems\PlatformHttpCacheBundle\PurgeClient\VarnishPurgeClient
arguments: ['@ezplatform.http_cache.cache_manager']
tags:
- {name: ezplatform.http_cache.purge_client, purge_type: http}
- {name: ezplatform.http_cache.purge_client, purge_type: varnish}

ezplatform.http_cache.purge_client.local:
class: EzSystems\PlatformHttpCacheBundle\PurgeClient\LocalPurgeClient
arguments: ["@ezplatform.http_cache.store"]
arguments: ['@ezplatform.http_cache.store']
tags:
- {name: ezplatform.http_cache.purge_client, purge_type: local}

ezplatform.http_cache.store:
alias: ezplatform.http_cache.tag_aware_store

ezplatform.http_cache.tag_aware_store:
class: EzSystems\PlatformHttpCacheBundle\Proxy\TagAwareStore
arguments: ["%ezplatform.http_cache.store.root%"]
arguments: ['%ezplatform.http_cache.store.root%']

ezplatform.http_cache.tag_handler:
alias: ezplatform.http_cache.tag_handler.xkey

ezplatform.http_cache.tag_handler.xkey:
class: EzSystems\PlatformHttpCacheBundle\Handler\TagHandler
arguments:
- '@ezplatform.http_cache.cache_manager'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,21 @@
*/
namespace EzSystems\PlatformHttpCacheBundle\Tests\PurgeClient;

use EzSystems\PlatformHttpCacheBundle\PurgeClient\FOSPurgeClient;
use EzSystems\PlatformHttpCacheBundle\PurgeClient\VarnishPurgeClient;
use FOS\HttpCache\ProxyClient\ProxyClientInterface;
use FOS\HttpCacheBundle\CacheManager;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;

class FOSPurgeClientTest extends TestCase
class VarnishPurgeClientTest extends TestCase
{
/**
* @var \PHPUnit_Framework_MockObject_MockObject
*/
private $cacheManager;

/**
* @var FOSPurgeClient
* @var VarnishPurgeClient
*/
private $purgeClient;

Expand All @@ -39,7 +39,7 @@ protected function setUp()
)
)
->getMock();
$this->purgeClient = new FOSPurgeClient($this->cacheManager);
$this->purgeClient = new VarnishPurgeClient($this->cacheManager);
}

public function testPurgeNoLocationIds()
Expand Down