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
26 changes: 26 additions & 0 deletions doc/4-events.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,29 @@ You can listen to the following events:
**ElementInvalidationEvent**: Triggered before a Pimcore element is invalidated; allows canceling the invalidation process or performing custom actions.

This allows you to add additional tags, cancel the tagging/invalidation process, or implement custom logic.

### ElementInvalidationEvent: distinguishing update from delete

`ElementInvalidationEvent` exposes a `type` property of type `InvalidationType`, which tells you whether the invalidation was triggered by a save or a delete:

```php
use Neusta\Pimcore\HttpCacheBundle\Element\ElementInvalidationEvent;
use Neusta\Pimcore\HttpCacheBundle\Element\InvalidationType;
use Symfony\Component\EventDispatcher\Attribute\AsEventListener;

#[AsEventListener]
final class MyInvalidationListener
{
public function __invoke(ElementInvalidationEvent $event): void
{
if (InvalidationType::Delete === $event->type) {
// React differently on delete vs update
}
}
}
```

| `InvalidationType` | Triggered by |
|---|---|
| `InvalidationType::Update` | Element saved (`POST_UPDATE`) |
| `InvalidationType::Delete` | Element deleted (`PRE_DELETE`) |
4 changes: 3 additions & 1 deletion src/Element/ElementInvalidationEvent.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,17 @@ final class ElementInvalidationEvent extends Event
public bool $cancel = false;

private function __construct(
public readonly InvalidationType $type,
public readonly ElementInterface $element,
public readonly ElementType $elementType,
private CacheTags $cacheTags,
) {
}

public static function fromElement(ElementInterface $element): self
public static function fromElement(InvalidationType $type, ElementInterface $element): self
{
return new self(
$type,
$element,
ElementType::fromElement($element),
CacheTags::fromElement($element),
Expand Down
8 changes: 4 additions & 4 deletions src/Element/InvalidateElementListener.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,17 +21,17 @@ public function onUpdate(ElementEventInterface $event): void
return;
}

$this->invalidateElement($event->getElement());
$this->invalidateElement(InvalidationType::Update, $event->getElement());
}

public function onDelete(ElementEventInterface $event): void
{
$this->invalidateElement($event->getElement());
$this->invalidateElement(InvalidationType::Delete, $event->getElement());
}

private function invalidateElement(ElementInterface $element): void
private function invalidateElement(InvalidationType $type, ElementInterface $element): void
{
$invalidationEvent = $this->dispatcher->dispatch(ElementInvalidationEvent::fromElement($element));
$invalidationEvent = $this->dispatcher->dispatch(ElementInvalidationEvent::fromElement($type, $element));
\assert($invalidationEvent instanceof ElementInvalidationEvent);

if ($invalidationEvent->cancel) {
Expand Down
9 changes: 9 additions & 0 deletions src/Element/InvalidationType.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?php declare(strict_types=1);

namespace Neusta\Pimcore\HttpCacheBundle\Element;

enum InvalidationType
{
case Update;
case Delete;
}
16 changes: 8 additions & 8 deletions tests/Unit/Cache/ResponseTagger/TraceableResponseTaggerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,31 +14,31 @@ final class TraceableResponseTaggerTest extends TestCase
{
use ProphecyTrait;

private TraceableResponseTagger $collectTagsResponseTagger;
private TraceableResponseTagger $traceableResponseTagger;

/** @var ObjectProphecy<ResponseTagger> */
private ObjectProphecy $innerTagger;

protected function setUp(): void
{
$this->innerTagger = $this->prophesize(ResponseTagger::class);
$this->collectTagsResponseTagger = new TraceableResponseTagger($this->innerTagger->reveal());
$this->traceableResponseTagger = new TraceableResponseTagger($this->innerTagger->reveal());
}

/**
* @test
*/
public function tag_should_collect_tags(): void
{
$this->collectTagsResponseTagger->tag(
$this->traceableResponseTagger->tag(
new CacheTags(
CacheTag::fromString('tag1'),
CacheTag::fromString('tag2'),
));

self::assertSame(
'tag1,tag2',
$this->collectTagsResponseTagger->recordedTags->toString(),
$this->traceableResponseTagger->recordedTags->toString(),
);
}

Expand All @@ -52,7 +52,7 @@ public function tag_should_forward_tags_to_inner_tagger(): void
CacheTag::fromString('tag2'),
);

$this->collectTagsResponseTagger->tag($tags);
$this->traceableResponseTagger->tag($tags);

$this->innerTagger->tag($tags)->shouldHaveBeenCalledOnce();
}
Expand All @@ -62,16 +62,16 @@ public function tag_should_forward_tags_to_inner_tagger(): void
*/
public function reset_should_reset_collected_tags(): void
{
$this->collectTagsResponseTagger->tag(
$this->traceableResponseTagger->tag(
new CacheTags(
CacheTag::fromString('tag1'),
CacheTag::fromString('tag2'),
));

$this->collectTagsResponseTagger->reset();
$this->traceableResponseTagger->reset();

self::assertTrue(
$this->collectTagsResponseTagger->recordedTags->isEmpty(),
$this->traceableResponseTagger->recordedTags->isEmpty(),
);
}
}
37 changes: 33 additions & 4 deletions tests/Unit/Element/InvalidateElementListenerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use Neusta\Pimcore\HttpCacheBundle\Cache\CacheTags;
use Neusta\Pimcore\HttpCacheBundle\Element\ElementInvalidationEvent;
use Neusta\Pimcore\HttpCacheBundle\Element\InvalidateElementListener;
use Neusta\Pimcore\HttpCacheBundle\Element\InvalidationType;
use PHPUnit\Framework\TestCase;
use Pimcore\Event\Model\AssetEvent;
use Pimcore\Event\Model\DataObjectEvent;
Expand Down Expand Up @@ -113,7 +114,7 @@ public function onUpdate_should_invalidate_elements(ElementEventInterface $event
public function onUpdate_does_not_invalidate_when_event_was_canceled(ElementEventInterface $event): void
{
$element = $event->getElement();
$invalidationEvent = ElementInvalidationEvent::fromElement($element);
$invalidationEvent = ElementInvalidationEvent::fromElement(InvalidationType::Update, $element);
$invalidationEvent->cancel = true;

$this->eventDispatcher->dispatch(Argument::type(ElementInvalidationEvent::class))
Expand All @@ -135,7 +136,7 @@ public function onUpdate_should_invalidate_additional_tags_when_requested(Elemen
$element = $event->getElement();
$additionalTag = CacheTag::fromString('tag1');
$additionalTags = CacheTags::fromStrings(['tag2', 'tag3']);
$invalidationEvent = ElementInvalidationEvent::fromElement($element);
$invalidationEvent = ElementInvalidationEvent::fromElement(InvalidationType::Update, $element);
$invalidationEvent->addTag($additionalTag);
$invalidationEvent->addTags($additionalTags);
$expected = CacheTags::fromElement($element)->with($additionalTag, $additionalTags);
Expand Down Expand Up @@ -185,7 +186,7 @@ public function onDelete_should_invalidate_elements(ElementEventInterface $event
public function onDelete_does_not_invalidate_when_event_was_canceled(ElementEventInterface $event): void
{
$element = $event->getElement();
$invalidationEvent = ElementInvalidationEvent::fromElement($element);
$invalidationEvent = ElementInvalidationEvent::fromElement(InvalidationType::Delete, $element);
$invalidationEvent->cancel = true;

$this->eventDispatcher->dispatch(Argument::type(ElementInvalidationEvent::class))
Expand All @@ -207,7 +208,7 @@ public function onDelete_should_invalidate_additional_tags_when_requested(Elemen
$element = $event->getElement();
$additionalTag = CacheTag::fromString('tag1');
$additionalTags = CacheTags::fromStrings(['tag2', 'tag3']);
$invalidationEvent = ElementInvalidationEvent::fromElement($element);
$invalidationEvent = ElementInvalidationEvent::fromElement(InvalidationType::Delete, $element);
$invalidationEvent->addTag($additionalTag);
$invalidationEvent->addTags($additionalTags);
$expected = CacheTags::fromElement($element)->with($additionalTag, $additionalTags);
Expand All @@ -221,6 +222,34 @@ public function onDelete_should_invalidate_additional_tags_when_requested(Elemen
->shouldHaveBeenCalledOnce();
}

/**
* @test
*
* @dataProvider elementProvider
*/
public function onUpdate_should_dispatch_event_with_update_type(ElementEventInterface $event): void
{
$this->invalidateElementListener->onUpdate($event);

$this->eventDispatcher->dispatch(Argument::that(
static fn (ElementInvalidationEvent $e) => InvalidationType::Update === $e->type,
))->shouldHaveBeenCalledOnce();
}

/**
* @test
*
* @dataProvider elementProvider
*/
public function onDelete_should_dispatch_event_with_delete_type(ElementEventInterface $event): void
{
$this->invalidateElementListener->onDelete($event);

$this->eventDispatcher->dispatch(Argument::that(
static fn (ElementInvalidationEvent $e) => InvalidationType::Delete === $e->type,
))->shouldHaveBeenCalledOnce();
}

public function elementProvider(): iterable
{
$asset = $this->prophesize(Asset::class);
Expand Down