Skip to content

Commit

Permalink
EZP-28183: Fix REST http cache on move operations (and more) (#37)
Browse files Browse the repository at this point in the history
With this bundle, REST HttpCache is not cleared when moving content,
editing content types, (...) And given the time it will take to fix
REST server to return data that can be used for ResponseTaggers and
how this also affects custum responses given, as we now only purge
by specific tags. Adding this is thus safests.

This somewhat brings back what @Plopix suggested in #21, essentially making sure we
add all tags also to X-Location responses by loading location, but to be on the safe
side it does it using sudo() and catching NotFound. Opted not to reuse ReponseTaggers
here as they don't fully fit, and as we want to rewrite this header independently of
if view cache is enabled or not.
  • Loading branch information
andrerom authored Nov 27, 2017
1 parent 2ffb3f0 commit f0f3916
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 17 deletions.
66 changes: 56 additions & 10 deletions spec/EventSubscriber/XLocationIdResponseSubscriberSpec.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,12 @@
*/
namespace spec\EzSystems\PlatformHttpCacheBundle\EventSubscriber;

use eZ\Publish\API\Repository\Values\Content\ContentInfo;
use eZ\Publish\Core\Base\Exceptions\NotFoundException;
use eZ\Publish\Core\Repository\Repository;
use eZ\Publish\Core\Repository\Values\Content\Location;
use PhpSpec\ObjectBehavior;
use Prophecy\Argument;
use Prophecy\Argument\Token\AnyValueToken;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\ResponseHeaderBag;
use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
Expand All @@ -18,12 +22,13 @@ public function let(
FilterResponseEvent $event,
Response $response,
TagHandlerInterface $tagHandler,
Repository $repository,
ResponseHeaderBag $responseHeaders
) {
$response->headers = $responseHeaders;
$event->getResponse()->willReturn($response);

$this->beConstructedWith($tagHandler);
$this->beConstructedWith($tagHandler, $repository);
}

public function it_does_not_rewrite_header_if_there_is_none(
Expand All @@ -36,31 +41,72 @@ public function it_does_not_rewrite_header_if_there_is_none(
$this->rewriteCacheHeader($event);
}

public function it_rewrite_header_if_there(
public function it_rewrite_header_with_location_info(
FilterResponseEvent $event,
Response $response,
TagHandlerInterface $tagHandler,
Repository $repository,
ResponseHeaderBag $responseHeaders
) {
$responseHeaders->has('X-Location-Id')->willReturn(true);
$responseHeaders->get('X-Location-Id')->willReturn('123');
$responseHeaders->has('Surrogate-Key')->willReturn(false);

$responseHeaders->set('Surrogate-Key', ['location-123'])->willReturn(null);
$responseHeaders->remove('X-Location-Id')->willReturn(null);
$repository->sudo(new AnyValueToken())->willReturn(
new Location([
'id' => 123,
'parentLocationId' => 2,
'pathString' => '/1/2/123/',
'contentInfo' => new ContentInfo(['id' => 101, 'contentTypeId' => 3, 'mainLocationId' => 120])
])
);

$tagHandler->addTagHeaders($response, [
'location-123',
'parent-2',
'path-1',
'path-2',
'path-123',
'content-101',
'content-type-3',
'location-120',
])->shouldBecalled();
$responseHeaders->remove('X-Location-Id')->shouldBecalled();

$this->rewriteCacheHeader($event);
}

public function it_rewrite_header_on_not_found_location(
FilterResponseEvent $event,
Response $response,
TagHandlerInterface $tagHandler,
Repository $repository,
ResponseHeaderBag $responseHeaders
) {
$responseHeaders->has('X-Location-Id')->willReturn(true);
$responseHeaders->get('X-Location-Id')->willReturn('123');

$repository->sudo(new AnyValueToken())->willThrow(new NotFoundException('id', 123));

$tagHandler->addTagHeaders($response, ['location-123', 'path-123'])->shouldBecalled();
$responseHeaders->remove('X-Location-Id')->shouldBecalled();

$this->rewriteCacheHeader($event);
}

public function it_rewrite_header_also_in_unofficial_plural_form_and_merges_exisitng_value(
FilterResponseEvent $event,
Response $response,
TagHandlerInterface $tagHandler,
Repository $repository,
ResponseHeaderBag $responseHeaders
) {
$responseHeaders->has('X-Location-Id')->willReturn(true);
$responseHeaders->get('X-Location-Id')->willReturn('123,34');
$responseHeaders->has('Surrogate-Key')->willReturn(true);
$responseHeaders->get('Surrogate-Key', null, false)->willReturn(['content-44']);

$responseHeaders->set('Surrogate-Key', ['content-44', 'location-123', 'location-34'])->willReturn(null);
$responseHeaders->remove('X-Location-Id')->willReturn(null);
$repository->sudo(new AnyValueToken())->willThrow(new NotFoundException('id', 123));

$tagHandler->addTagHeaders($response, ['location-123', 'path-123', 'location-34', 'path-34'])->shouldBecalled();
$responseHeaders->remove('X-Location-Id')->shouldBecalled();

$this->rewriteCacheHeader($event);
}
Expand Down
38 changes: 32 additions & 6 deletions src/EventSubscriber/XLocationIdResponseSubscriber.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
*/
namespace EzSystems\PlatformHttpCacheBundle\EventSubscriber;

use eZ\Publish\API\Repository\Exceptions\NotFoundException;
use eZ\Publish\API\Repository\Repository;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
use Symfony\Component\HttpKernel\KernelEvents;
Expand All @@ -22,14 +24,16 @@ class XLocationIdResponseSubscriber implements EventSubscriberInterface
{
const LOCATION_ID_HEADER = 'X-Location-Id';

/**
* @var EzSystems\PlatformHttpCacheBundle\Handler\TagHandlerInterface
*/
/** @var \EzSystems\PlatformHttpCacheBundle\Handler\TagHandlerInterface */
private $tagHandler;

public function __construct(TagHandlerInterface $tagHandler)
/** @var \eZ\Publish\API\Repository\Repository */
private $repository;

public function __construct(TagHandlerInterface $tagHandler, Repository $repository)
{
$this->tagHandler = $tagHandler;
$this->repository = $repository;
}

public static function getSubscribedEvents()
Expand All @@ -53,8 +57,30 @@ public function rewriteCacheHeader(FilterResponseEvent $event)
$tags = [];
foreach (explode(',', $response->headers->get(static::LOCATION_ID_HEADER)) as $id) {
$id = trim($id);
$tags[] = "location-$id";
$tags[] = "path-$id";
try {
/** @var $location \eZ\Publish\API\Repository\Values\Content\Location */
$location = $this->repository->sudo(function (Repository $repository) use ($id) {
return $repository->getLocationService()->loadLocation($id);
});

$tags[] = 'location-' . $location->id;
$tags[] = 'parent-' . $location->parentLocationId;

foreach ($location->path as $pathItem) {
$tags[] = 'path-' . $pathItem;
}

$contentInfo = $location->getContentInfo();
$tags[] = 'content-' . $contentInfo->id;
$tags[] = 'content-type-' . $contentInfo->contentTypeId;

if ($contentInfo->mainLocationId !== $location->id) {
$tags[] = 'location-' . $contentInfo->mainLocationId;
}
} catch (NotFoundException $e) {
$tags[] = "location-$id";
$tags[] = "path-$id";
}
}

$this->tagHandler->addTagHeaders($response, array_unique($tags));
Expand Down
2 changes: 1 addition & 1 deletion src/Resources/config/view_cache.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ services:

ezplatform.x_location_id.response_subscriber:
class: EzSystems\PlatformHttpCacheBundle\EventSubscriber\XLocationIdResponseSubscriber
arguments: ['@ezplatform.http_cache.tag_handler']
arguments: ['@ezplatform.http_cache.tag_handler', '@ezpublish.api.repository']
tags:
- { name: kernel.event_subscriber }

Expand Down

0 comments on commit f0f3916

Please sign in to comment.