diff --git a/config/services.php b/config/services.php index da95c24..792939c 100644 --- a/config/services.php +++ b/config/services.php @@ -91,7 +91,8 @@ $services->set('neusta_pimcore_http_cache.element.invalidate_listener', InvalidateElementListener::class) ->arg('$cacheInvalidator', service('neusta_pimcore_http_cache.cache_invalidator')) - ->arg('$dispatcher', service('event_dispatcher')); + ->arg('$dispatcher', service('event_dispatcher')) + ->arg('$elementRepository', service('.neusta_pimcore_http_cache.element.repository')); $services->set('neusta_pimcore_http_cache.data_collector', DataCollector::class) ->arg('$cacheTagCollector', service('.neusta_pimcore_http_cache.collect_tags_response_tagger')) diff --git a/src/Element/InvalidateElementListener.php b/src/Element/InvalidateElementListener.php index d8a2d8f..ec08bd7 100644 --- a/src/Element/InvalidateElementListener.php +++ b/src/Element/InvalidateElementListener.php @@ -4,6 +4,7 @@ use Neusta\Pimcore\HttpCacheBundle\Cache\CacheInvalidator; use Pimcore\Event\Model\ElementEventInterface; +use Pimcore\Model\Dependency; use Pimcore\Model\Element\ElementInterface; use Symfony\Component\EventDispatcher\EventDispatcherInterface; @@ -12,6 +13,7 @@ final class InvalidateElementListener public function __construct( private readonly CacheInvalidator $cacheInvalidator, private readonly EventDispatcherInterface $dispatcher, + private readonly ElementRepository $elementRepository, ) { } @@ -21,12 +23,24 @@ public function onUpdate(ElementEventInterface $event): void return; } - $this->invalidateElement($event->getElement()); + $element = $event->getElement(); + + $this->invalidateElement($element); + + if (ElementType::Object === ElementType::tryFrom($element->getType())) { + $this->invalidateDependencies($element->getDependencies()); + } } public function onDelete(ElementEventInterface $event): void { - $this->invalidateElement($event->getElement()); + $element = $event->getElement(); + + $this->invalidateElement($element); + + if (ElementType::Object === ElementType::tryFrom($element->getType())) { + $this->invalidateDependencies($element->getDependencies()); + } } private function invalidateElement(ElementInterface $element): void @@ -40,4 +54,24 @@ private function invalidateElement(ElementInterface $element): void $this->cacheInvalidator->invalidate($invalidationEvent->cacheTags()); } + + private function invalidateDependencies(Dependency $dependency): void + { + foreach ($dependency->getRequiredBy() as $required) { + if (!isset($required['id'], $required['type'])) { + continue; + } + + $element = match (ElementType::tryFrom($required['type'])) { + ElementType::Object => $this->elementRepository->findObject($required['id']), + ElementType::Document => $this->elementRepository->findDocument($required['id']), + ElementType::Asset => $this->elementRepository->findAsset($required['id']), + default => null, + }; + + if ($element) { + $this->invalidateElement($element); + } + } + } } diff --git a/tests/Integration/Configuration/CollectConfigurationDataTest.php b/tests/Integration/Configuration/CollectConfigurationDataTest.php index d0e1870..32edb6a 100644 --- a/tests/Integration/Configuration/CollectConfigurationDataTest.php +++ b/tests/Integration/Configuration/CollectConfigurationDataTest.php @@ -40,7 +40,7 @@ protected function setUp(): void ])] public function collects_configuration_data(): void { - self::arrange(fn () => TestDocumentFactory::simplePage())->save(); + self::arrange(fn () => TestDocumentFactory::simplePage(5))->save(); $this->client->request('GET', '/test_document_page'); $this->client->enableProfiler(); @@ -65,7 +65,7 @@ public function collects_configuration_data(): void ])] public function does_not_collect_configuration_data_when_profiler_is_disabled(): void { - self::arrange(fn () => TestDocumentFactory::simplePage())->save(); + self::arrange(fn () => TestDocumentFactory::simplePage(5))->save(); $this->client->request('GET', '/test_document_page'); $this->client->enableProfiler(); diff --git a/tests/Integration/Helpers/TestAssetFactory.php b/tests/Integration/Helpers/TestAssetFactory.php index 5e075e9..168b82c 100644 --- a/tests/Integration/Helpers/TestAssetFactory.php +++ b/tests/Integration/Helpers/TestAssetFactory.php @@ -6,11 +6,11 @@ final class TestAssetFactory { - public static function simpleAsset(): Asset + public static function simpleAsset(int $id, string $fileName = 'test-asset.txt'): Asset { $asset = new Asset(); - $asset->setId(42); - $asset->setFilename('test-asset.txt'); + $asset->setId($id); + $asset->setFilename($fileName); $asset->setParentId(1); $asset->setData('This is the content of the test asset.'); $asset->setMimetype('text/plain'); @@ -18,22 +18,22 @@ public static function simpleAsset(): Asset return $asset; } - public static function simpleImage(): Asset\Image + public static function simpleImage(int $id, string $fileName = 'test-asset.jpg'): Asset\Image { $image = new Asset\Image(); - $image->setId(17); - $image->setFilename('test-asset.jpg'); + $image->setId($id); + $image->setFilename($fileName); $image->setParentId(1); $image->setMimetype('image/jpeg'); return $image; } - public static function simpleFolder(): Asset\Folder + public static function simpleFolder(int $id, string $key = 'test-asset-folder'): Asset\Folder { $folder = new Asset\Folder(); - $folder->setKey('test-asset-folder'); - $folder->setId(23); + $folder->setId($id); + $folder->setKey($key); $folder->setParentId(1); return $folder; diff --git a/tests/Integration/Helpers/TestDocumentFactory.php b/tests/Integration/Helpers/TestDocumentFactory.php index 7f7c4eb..489484e 100644 --- a/tests/Integration/Helpers/TestDocumentFactory.php +++ b/tests/Integration/Helpers/TestDocumentFactory.php @@ -2,6 +2,8 @@ namespace Neusta\Pimcore\HttpCacheBundle\Tests\Integration\Helpers; +use Pimcore\Model\DataObject\TestObject; +use Pimcore\Model\Document\Editable\Relation; use Pimcore\Model\Document\Email; use Pimcore\Model\Document\Folder; use Pimcore\Model\Document\Hardlink; @@ -10,55 +12,67 @@ final class TestDocumentFactory { - public static function simplePage(): Page + public static function simplePage(int $id, string $key = 'test_document_page', ?TestObject $relatedObject = null): Page { $page = new Page(); - $page->setId(42); - $page->setKey('test_document_page'); + $page->setId($id); + $page->setKey($key); $page->setPublished(true); $page->setParentId(1); + if (null !== $relatedObject) { + $objectRelation = new Relation(); + $objectRelation->setName('relatedObject'); + $objectRelation->setDataFromResource([ + 'id' => $relatedObject->getId(), + 'type' => 'object', + 'subtype' => 'object', + ]); + + $page->setEditable($objectRelation); + } + return $page; } - public static function simpleSnippet(): Snippet + public static function simpleSnippet(int $id, string $key = 'test_document_snippet'): Snippet { $snippet = new Snippet(); - $snippet->setId(23); - $snippet->setKey('test_document_snippet'); + $snippet->setId($id); + $snippet->setKey($key); $snippet->setPublished(true); $snippet->setParentId(1); return $snippet; } - public static function simpleEmail(): Email + public static function simpleEmail(int $id, string $key = 'test_document_email'): Email { $email = new Email(); - $email->setId(17); - $email->setKey('test_document_link'); + $email->setId($id); + $email->setKey($key); $email->setPublished(true); $email->setParentId(1); return $email; } - public static function simpleHardLink(): Hardlink + public static function simpleHardLink(int $id, string $key = 'test_document_hard_link'): Hardlink { $hardlink = new Hardlink(); - $hardlink->setId(33); - $hardlink->setKey('test_document_hard_link'); + $hardlink->setId($id); + $hardlink->setKey($key); $hardlink->setPublished(true); $hardlink->setParentId(1); return $hardlink; } - public static function simpleFolder(): Folder + public static function simpleFolder(int $id, string $key = 'test_document_folder'): Folder { $folder = new Folder(); - $folder->setId(97); - $folder->setKey('test_document_folder'); + $folder->setId($id); + $folder->setKey($key); $folder->setPublished(true); $folder->setParentId(1); diff --git a/tests/Integration/Helpers/TestObjectFactory.php b/tests/Integration/Helpers/TestObjectFactory.php index 98d9f42..7e317c4 100644 --- a/tests/Integration/Helpers/TestObjectFactory.php +++ b/tests/Integration/Helpers/TestObjectFactory.php @@ -2,29 +2,35 @@ namespace Neusta\Pimcore\HttpCacheBundle\Tests\Integration\Helpers; +use Pimcore\Image; use Pimcore\Model\DataObject; use Pimcore\Model\DataObject\AbstractObject; -use Pimcore\Model\DataObject\TestDataObject; +use Pimcore\Model\DataObject\TestObject; +use Pimcore\Model\Document\Page; final class TestObjectFactory { - public static function simpleObject(): TestDataObject + /** + * @param list $related + */ + public static function simpleObject(int $id, string $key = 'test_object', array $related = []): TestObject { - $object = new TestDataObject(); - $object->setId(42); - $object->setKey('test_object'); + $object = new TestObject(); + $object->setId($id); + $object->setKey($key); $object->setContent('Test content'); + $object->setRelated($related); $object->setPublished(true); $object->setParentId(1); return $object; } - public static function simpleVariant(): TestDataObject + public static function simpleVariant(int $id, string $key = 'simple_variant'): TestObject { - $object = new TestDataObject(); - $object->setId(17); - $object->setKey('test_variant'); + $object = new TestObject(); + $object->setId($id); + $object->setKey($key); $object->setContent('Test content'); $object->setPublished(true); $object->setParentId(1); @@ -33,11 +39,11 @@ public static function simpleVariant(): TestDataObject return $object; } - public static function simpleFolder(): DataObject\Folder + public static function simpleFolder(int $id, string $key = 'simple_folder'): DataObject\Folder { $folder = new DataObject\Folder(); - $folder->setId(23); - $folder->setKey('test_folder'); + $folder->setId($id); + $folder->setKey($key); $folder->setParentId(1); return $folder; diff --git a/tests/Integration/Invalidation/CancelInvalidationTest.php b/tests/Integration/Invalidation/CancelInvalidationTest.php index ec9364c..5462afe 100644 --- a/tests/Integration/Invalidation/CancelInvalidationTest.php +++ b/tests/Integration/Invalidation/CancelInvalidationTest.php @@ -45,7 +45,7 @@ protected function setUp(): void ])] public function cancel_invalidation_on_object_update(): void { - $object = self::arrange(fn () => TestObjectFactory::simpleObject()->save()); + $object = self::arrange(fn () => TestObjectFactory::simpleObject(42)->save()); $object->setContent('Updated test content')->save(); @@ -62,7 +62,7 @@ public function cancel_invalidation_on_object_update(): void ])] public function cancel_invalidation_on_document_update(): void { - $document = self::arrange(fn () => TestDocumentFactory::simplePage()->save()); + $document = self::arrange(fn () => TestDocumentFactory::simplePage(5)->save()); $document->setKey('updated_test_document_page')->save(); @@ -79,7 +79,7 @@ public function cancel_invalidation_on_document_update(): void ])] public function cancel_invalidation_on_asset_update(): void { - $asset = self::arrange(fn () => TestAssetFactory::simpleAsset()->save()); + $asset = self::arrange(fn () => TestAssetFactory::simpleAsset(5)->save()); $asset->setData('Updated test content')->save(); @@ -96,7 +96,7 @@ public function cancel_invalidation_on_asset_update(): void ])] public function cancel_invalidation_on_object_delete(): void { - $object = self::arrange(fn () => TestObjectFactory::simpleObject()->save()); + $object = self::arrange(fn () => TestObjectFactory::simpleObject(42)->save()); $object->delete(); @@ -113,7 +113,7 @@ public function cancel_invalidation_on_object_delete(): void ])] public function cancel_invalidation_on_document_delete(): void { - $document = self::arrange(fn () => TestDocumentFactory::simplePage()->save()); + $document = self::arrange(fn () => TestDocumentFactory::simplePage(5)->save()); $document->delete(); @@ -130,7 +130,7 @@ public function cancel_invalidation_on_document_delete(): void ])] public function cancel_invalidation_on_asset_delete(): void { - $asset = self::arrange(fn () => TestAssetFactory::simpleAsset()->save()); + $asset = self::arrange(fn () => TestAssetFactory::simpleAsset(5)->save()); $asset->delete(); diff --git a/tests/Integration/Invalidation/InvalidateAdditionalTagTest.php b/tests/Integration/Invalidation/InvalidateAdditionalTagTest.php index 55f8662..402af43 100644 --- a/tests/Integration/Invalidation/InvalidateAdditionalTagTest.php +++ b/tests/Integration/Invalidation/InvalidateAdditionalTagTest.php @@ -53,7 +53,7 @@ protected function setUp(): void ])] public function invalidate_additional_tag_on_object_update(): void { - $object = self::arrange(fn () => TestObjectFactory::simpleObject()->save()); + $object = self::arrange(fn () => TestObjectFactory::simpleObject(42)->save()); $object->setContent('Updated test content')->save(); @@ -73,7 +73,7 @@ public function invalidate_additional_tag_on_object_update(): void ])] public function does_not_invalidate_additional_tag_on_object_update_when_cache_type_is_disabled(): void { - $object = self::arrange(fn () => TestObjectFactory::simpleObject()->save()); + $object = self::arrange(fn () => TestObjectFactory::simpleObject(42)->save()); $object->setKey('updated_test_object')->save(); @@ -93,11 +93,11 @@ public function does_not_invalidate_additional_tag_on_object_update_when_cache_t ])] public function invalidate_additional_tag_on_document_update(): void { - $document = self::arrange(fn () => TestDocumentFactory::simplePage()->save()); + $document = self::arrange(fn () => TestDocumentFactory::simplePage(5)->save()); $document->setKey('updated_test_document_page')->save(); - $this->cacheManager->invalidateTags(['d42', 'foo-bar'])->shouldHaveBeenCalledTimes(1); + $this->cacheManager->invalidateTags(['d5', 'foo-bar'])->shouldHaveBeenCalledTimes(1); } /** @@ -113,11 +113,11 @@ public function invalidate_additional_tag_on_document_update(): void ])] public function does_not_invalidate_additional_tag_on_document_update_when_cache_type_is_disabled(): void { - $document = self::arrange(fn () => TestDocumentFactory::simplePage()->save()); + $document = self::arrange(fn () => TestDocumentFactory::simplePage(5)->save()); $document->setKey('updated_test_document_page')->save(); - $this->cacheManager->invalidateTags(['d42', 'foo-bar'])->shouldNotHaveBeenCalled(); + $this->cacheManager->invalidateTags(['d5', 'foo-bar'])->shouldNotHaveBeenCalled(); } /** @@ -133,11 +133,11 @@ public function does_not_invalidate_additional_tag_on_document_update_when_cache ])] public function invalidate_additional_tag_on_asset_update(): void { - $asset = self::arrange(fn () => TestAssetFactory::simpleAsset()->save()); + $asset = self::arrange(fn () => TestAssetFactory::simpleAsset(5)->save()); $asset->setData('Updated test content')->save(); - $this->cacheManager->invalidateTags(['a42', 'foo-bar'])->shouldHaveBeenCalledTimes(1); + $this->cacheManager->invalidateTags(['a5', 'foo-bar'])->shouldHaveBeenCalledTimes(1); } /** @@ -153,11 +153,11 @@ public function invalidate_additional_tag_on_asset_update(): void ])] public function does_not_invalidate_additional_tag_on_asset_update_when_cache_type_is_disabled(): void { - $asset = self::arrange(fn () => TestAssetFactory::simpleAsset()->save()); + $asset = self::arrange(fn () => TestAssetFactory::simpleAsset(5)->save()); $asset->setData('Updated test content')->save(); - $this->cacheManager->invalidateTags(['a42', 'foo-bar'])->shouldNotHaveBeenCalled(); + $this->cacheManager->invalidateTags(['a5', 'foo-bar'])->shouldNotHaveBeenCalled(); } /** @@ -173,7 +173,7 @@ public function does_not_invalidate_additional_tag_on_asset_update_when_cache_ty ])] public function invalidate_additional_tag_on_object_deletion(): void { - $object = self::arrange(fn () => TestObjectFactory::simpleObject()->save()); + $object = self::arrange(fn () => TestObjectFactory::simpleObject(42)->save()); $object->delete(); @@ -193,7 +193,7 @@ public function invalidate_additional_tag_on_object_deletion(): void ])] public function does_not_invalidate_additional_tag_on_object_deletion_when_cache_type_is_disabled(): void { - $object = self::arrange(fn () => TestObjectFactory::simpleObject()->save()); + $object = self::arrange(fn () => TestObjectFactory::simpleObject(42)->save()); $object->delete(); @@ -213,11 +213,11 @@ public function does_not_invalidate_additional_tag_on_object_deletion_when_cache ])] public function invalidate_additional_tag_on_asset_deletion(): void { - $asset = self::arrange(fn () => TestAssetFactory::simpleAsset()->save()); + $asset = self::arrange(fn () => TestAssetFactory::simpleAsset(5)->save()); $asset->delete(); - $this->cacheManager->invalidateTags(['a42', 'foo-bar'])->shouldHaveBeenCalledTimes(1); + $this->cacheManager->invalidateTags(['a5', 'foo-bar'])->shouldHaveBeenCalledTimes(1); } /** @@ -233,11 +233,11 @@ public function invalidate_additional_tag_on_asset_deletion(): void ])] public function does_not_invalidate_additional_tag_on_asset_deletion_when_cache_type_is_disabled(): void { - $asset = self::arrange(fn () => TestAssetFactory::simpleAsset()->save()); + $asset = self::arrange(fn () => TestAssetFactory::simpleAsset(5)->save()); $asset->delete(); - $this->cacheManager->invalidateTags(['a42', 'foo-bar'])->shouldNotHaveBeenCalled(); + $this->cacheManager->invalidateTags(['a5', 'foo-bar'])->shouldNotHaveBeenCalled(); } /** @@ -253,11 +253,11 @@ public function does_not_invalidate_additional_tag_on_asset_deletion_when_cache_ ])] public function invalidate_additional_tag_on_document_deletion(): void { - $document = self::arrange(fn () => TestDocumentFactory::simplePage()->save()); + $document = self::arrange(fn () => TestDocumentFactory::simplePage(5)->save()); $document->delete(); - $this->cacheManager->invalidateTags(['d42', 'foo-bar'])->shouldHaveBeenCalledTimes(1); + $this->cacheManager->invalidateTags(['d5', 'foo-bar'])->shouldHaveBeenCalledTimes(1); } /** @@ -273,10 +273,10 @@ public function invalidate_additional_tag_on_document_deletion(): void ])] public function does_not_invalidate_additional_tag_on_document_deletion_when_cache_type_was_disabled(): void { - $document = self::arrange(fn () => TestDocumentFactory::simplePage()->save()); + $document = self::arrange(fn () => TestDocumentFactory::simplePage(5)->save()); $document->delete(); - $this->cacheManager->invalidateTags(['d42', 'foo-bar'])->shouldNotHaveBeenCalled(); + $this->cacheManager->invalidateTags(['d5', 'foo-bar'])->shouldNotHaveBeenCalled(); } } diff --git a/tests/Integration/Invalidation/InvalidateAssetTest.php b/tests/Integration/Invalidation/InvalidateAssetTest.php index e66430d..cd26b65 100644 --- a/tests/Integration/Invalidation/InvalidateAssetTest.php +++ b/tests/Integration/Invalidation/InvalidateAssetTest.php @@ -34,9 +34,9 @@ protected function setUp(): void $this->cacheManager->invalidateTags(Argument::any())->willReturn($this->cacheManager->reveal()); self::getContainer()->set('fos_http_cache.cache_manager', $this->cacheManager->reveal()); - $this->asset = self::arrange(fn () => TestAssetFactory::simpleAsset()->save()); - $this->folder = self::arrange(fn () => TestAssetFactory::simpleFolder()->save()); - $this->image = self::arrange(fn () => TestAssetFactory::simpleImage()->save()); + $this->asset = self::arrange(fn () => TestAssetFactory::simpleAsset(5)->save()); + $this->folder = self::arrange(fn () => TestAssetFactory::simpleFolder(12)->save()); + $this->image = self::arrange(fn () => TestAssetFactory::simpleImage(29)->save()); } /** @@ -51,7 +51,7 @@ public function response_is_invalidated_when_asset_is_updated(): void { $this->asset->setData('Updated test content')->save(); - $this->cacheManager->invalidateTags(['a42'])->shouldHaveBeenCalledTimes(1); + $this->cacheManager->invalidateTags(['a5'])->shouldHaveBeenCalledTimes(1); } /** @@ -66,7 +66,7 @@ public function response_is_invalidated_when_asset_is_deleted(): void { $this->asset->delete(); - $this->cacheManager->invalidateTags(['a42'])->shouldHaveBeenCalledTimes(1); + $this->cacheManager->invalidateTags(['a5'])->shouldHaveBeenCalledTimes(1); } /** diff --git a/tests/Integration/Invalidation/InvalidateDocumentTest.php b/tests/Integration/Invalidation/InvalidateDocumentTest.php index 1618cbe..a421e91 100644 --- a/tests/Integration/Invalidation/InvalidateDocumentTest.php +++ b/tests/Integration/Invalidation/InvalidateDocumentTest.php @@ -3,8 +3,10 @@ namespace Neusta\Pimcore\HttpCacheBundle\Tests\Integration\Invalidation; use FOS\HttpCacheBundle\CacheManager; +use Neusta\Pimcore\HttpCacheBundle\Cache\CacheTag; use Neusta\Pimcore\HttpCacheBundle\Tests\Integration\Helpers\ArrangeCacheTest; use Neusta\Pimcore\HttpCacheBundle\Tests\Integration\Helpers\TestDocumentFactory; +use Neusta\Pimcore\HttpCacheBundle\Tests\Integration\Helpers\TestObjectFactory; use Neusta\Pimcore\TestingFramework\Database\ResetDatabase; use Neusta\Pimcore\TestingFramework\Test\Attribute\ConfigureExtension; use Neusta\Pimcore\TestingFramework\Test\ConfigurableKernelTestCase; @@ -36,10 +38,10 @@ protected function setUp(): void $this->cacheManager->invalidateTags(Argument::any())->willReturn($this->cacheManager->reveal()); self::getContainer()->set('fos_http_cache.cache_manager', $this->cacheManager->reveal()); - $this->document = self::arrange(fn () => TestDocumentFactory::simplePage()->save()); - $this->hardlink = self::arrange(fn () => TestDocumentFactory::simpleHardLink()->save()); - $this->email = self::arrange(fn () => TestDocumentFactory::simpleEmail()->save()); - $this->folder = self::arrange(fn () => TestDocumentFactory::simpleFolder()->save()); + $this->document = self::arrange(fn () => TestDocumentFactory::simplePage(5)->save()); + $this->hardlink = self::arrange(fn () => TestDocumentFactory::simpleHardLink(12)->save()); + $this->email = self::arrange(fn () => TestDocumentFactory::simpleEmail(29)->save()); + $this->folder = self::arrange(fn () => TestDocumentFactory::simpleFolder(70)->save()); } /** @@ -54,7 +56,31 @@ public function response_is_invalidated_when_document_is_updated(): void { $this->document->setKey('updated_test_document_page')->save(); - $this->cacheManager->invalidateTags(['d42'])->shouldHaveBeenCalledTimes(1); + $this->cacheManager->invalidateTags(['d5'])->shouldHaveBeenCalledTimes(1); + } + + /** + * @test + */ + #[ConfigureExtension('neusta_pimcore_http_cache', [ + 'elements' => [ + 'objects' => true, + 'documents' => true, + ], + ])] + public function dependent_document_is_invalidated_on_object_update(): void + { + $dependent = self::arrange( + fn () => TestObjectFactory::simpleObject(12)->save(), + ); + $document = self::arrange( + fn () => TestDocumentFactory::simplePage(96, 'other_test_document_page', $dependent)->save(), + ); + + $dependent->setContent('Updated test content')->save(); + + $this->cacheManager->invalidateTags([CacheTag::fromElement($document)->toString()]) + ->shouldHaveBeenCalledTimes(1); } /** @@ -69,7 +95,31 @@ public function response_is_invalidated_when_document_is_deleted(): void { $this->document->delete(); - $this->cacheManager->invalidateTags(['d42'])->shouldHaveBeenCalledTimes(1); + $this->cacheManager->invalidateTags(['d5'])->shouldHaveBeenCalledTimes(1); + } + + /** + * @test + */ + #[ConfigureExtension('neusta_pimcore_http_cache', [ + 'elements' => [ + 'objects' => true, + 'documents' => true, + ], + ])] + public function dependent_document_is_invalidated_on_object_deletion(): void + { + $dependent = self::arrange( + fn () => TestObjectFactory::simpleObject(12)->save(), + ); + $document = self::arrange( + fn () => TestDocumentFactory::simplePage(96, 'other_test_document_page', $dependent)->save(), + ); + + $dependent->delete(); + + $this->cacheManager->invalidateTags([CacheTag::fromElement($document)->toString()]) + ->shouldHaveBeenCalledTimes(1); } /** diff --git a/tests/Integration/Invalidation/InvalidateObjectTest.php b/tests/Integration/Invalidation/InvalidateObjectTest.php index a1c409f..182233d 100644 --- a/tests/Integration/Invalidation/InvalidateObjectTest.php +++ b/tests/Integration/Invalidation/InvalidateObjectTest.php @@ -3,13 +3,14 @@ namespace Neusta\Pimcore\HttpCacheBundle\Tests\Integration\Invalidation; use FOS\HttpCacheBundle\CacheManager; +use Neusta\Pimcore\HttpCacheBundle\Cache\CacheTag; use Neusta\Pimcore\HttpCacheBundle\Tests\Integration\Helpers\ArrangeCacheTest; use Neusta\Pimcore\HttpCacheBundle\Tests\Integration\Helpers\TestObjectFactory; use Neusta\Pimcore\TestingFramework\Database\ResetDatabase; use Neusta\Pimcore\TestingFramework\Test\Attribute\ConfigureExtension; use Neusta\Pimcore\TestingFramework\Test\ConfigurableKernelTestCase; use Pimcore\Model\DataObject; -use Pimcore\Model\DataObject\TestDataObject; +use Pimcore\Model\DataObject\TestObject; use Prophecy\Argument; use Prophecy\PhpUnit\ProphecyTrait; use Prophecy\Prophecy\ObjectProphecy; @@ -23,9 +24,9 @@ final class InvalidateObjectTest extends ConfigurableKernelTestCase /** @var ObjectProphecy */ private ObjectProphecy $cacheManager; - private TestDataObject $object; + private TestObject $object; - private TestDataObject $variant; + private TestObject $variant; private DataObject\Folder $folder; @@ -35,9 +36,9 @@ protected function setUp(): void $this->cacheManager->invalidateTags(Argument::any())->willReturn($this->cacheManager->reveal()); self::getContainer()->set('fos_http_cache.cache_manager', $this->cacheManager->reveal()); - $this->object = self::arrange(fn () => TestObjectFactory::simpleObject()->save()); - $this->folder = self::arrange(fn () => TestObjectFactory::simpleFolder()->save()); - $this->variant = self::arrange(fn () => TestObjectFactory::simpleVariant()->save()); + $this->object = self::arrange(fn () => TestObjectFactory::simpleObject(5)->save()); + $this->folder = self::arrange(fn () => TestObjectFactory::simpleFolder(29)->save()); + $this->variant = self::arrange(fn () => TestObjectFactory::simpleVariant(70)->save()); } /** @@ -52,7 +53,28 @@ public function response_is_invalidated_when_object_is_updated(): void { $this->object->setContent('Updated test content')->save(); - $this->cacheManager->invalidateTags(['o42'])->shouldHaveBeenCalledTimes(1); + $this->cacheManager->invalidateTags([CacheTag::fromElement($this->object)->toString()]) + ->shouldHaveBeenCalledTimes(1); + } + + /** + * @test + */ + #[ConfigureExtension('neusta_pimcore_http_cache', [ + 'elements' => [ + 'objects' => true, + ], + ])] + public function dependent_object_is_invalidated_on_object_update(): void + { + $dependent = self::arrange( + fn () => TestObjectFactory::simpleObject(12, 'other_test_object', [$this->object])->save(), + ); + + $this->object->setContent('Updated test content')->save(); + + $this->cacheManager->invalidateTags([CacheTag::fromElement($dependent)->toString()]) + ->shouldHaveBeenCalledTimes(1); } /** @@ -67,7 +89,28 @@ public function response_is_invalidated_when_object_is_deleted(): void { $this->object->delete(); - $this->cacheManager->invalidateTags(['o42'])->shouldHaveBeenCalledTimes(1); + $this->cacheManager->invalidateTags([CacheTag::fromElement($this->object)->toString()]) + ->shouldHaveBeenCalledTimes(1); + } + + /** + * @test + */ + #[ConfigureExtension('neusta_pimcore_http_cache', [ + 'elements' => [ + 'objects' => true, + ], + ])] + public function dependent_object_is_invalidated_on_object_deletion(): void + { + $dependent = self::arrange( + fn () => TestObjectFactory::simpleObject(12, 'other_test_object', [$this->object])->save(), + ); + + $this->object->delete(); + + $this->cacheManager->invalidateTags([CacheTag::fromElement($dependent)->toString()]) + ->shouldHaveBeenCalledTimes(1); } /** @@ -148,7 +191,7 @@ public function response_is_not_invalidated_when_specified_type_is_disabled_on_d 'objects' => [ 'enabled' => true, 'classes' => [ - 'TestDataObject' => false, + 'TestObject' => false, ], ], ], @@ -168,7 +211,7 @@ public function response_is_not_invalidated_when_custom_data_object_class_is_dis 'objects' => [ 'enabled' => true, 'classes' => [ - 'TestDataObject' => false, + 'TestObject' => false, ], ], ], diff --git a/tests/Integration/Tagging/CollectTagsDataTest.php b/tests/Integration/Tagging/CollectTagsDataTest.php index 6a83a95..de3cab4 100644 --- a/tests/Integration/Tagging/CollectTagsDataTest.php +++ b/tests/Integration/Tagging/CollectTagsDataTest.php @@ -46,7 +46,7 @@ protected function setUp(): void #[ConfigureRoute(__DIR__ . '/../Fixtures/get_document_route.php')] public function collect_tags_for_type_document(): void { - self::arrange(fn () => TestDocumentFactory::simplePage())->save(); + self::arrange(fn () => TestDocumentFactory::simplePage(5))->save(); $this->client->request('GET', '/test_document_page'); $this->client->enableProfiler(); @@ -55,7 +55,7 @@ public function collect_tags_for_type_document(): void self::assertInstanceOf(DataCollector::class, $dataCollector); self::assertSame( - [['tag' => 'd1', 'type' => 'document'], ['tag' => 'd42', 'type' => 'document']], + [['tag' => 'd1', 'type' => 'document'], ['tag' => 'd5', 'type' => 'document']], $dataCollector->getTags(), ); } @@ -71,16 +71,16 @@ public function collect_tags_for_type_document(): void #[ConfigureRoute(__DIR__ . '/../Fixtures/get_object_route.php')] public function collect_tags_for_type_object(): void { - self::arrange(fn () => TestObjectFactory::simpleObject()->save()); + self::arrange(fn () => TestObjectFactory::simpleObject(5)->save()); - $this->client->request('GET', '/get-object?id=42'); + $this->client->request('GET', '/get-object?id=5'); $this->client->enableProfiler(); $dataCollector = $this->client->getProfile()->getCollector('pimcore_http_cache'); self::assertInstanceOf(DataCollector::class, $dataCollector); self::assertSame( - [['tag' => 'o42', 'type' => 'object']], + [['tag' => 'o5', 'type' => 'object']], $dataCollector->getTags(), ); } @@ -96,16 +96,16 @@ public function collect_tags_for_type_object(): void #[ConfigureRoute(__DIR__ . '/../Fixtures/get_asset_route.php')] public function collect_tags_of_type_asset(): void { - self::arrange(fn () => TestAssetFactory::simpleAsset()->save()); + self::arrange(fn () => TestAssetFactory::simpleAsset(5)->save()); - $this->client->request('GET', '/get-asset?id=42'); + $this->client->request('GET', '/get-asset?id=5'); $this->client->enableProfiler(); $dataCollector = $this->client->getProfile()->getCollector('pimcore_http_cache'); self::assertInstanceOf(DataCollector::class, $dataCollector); self::assertSame( - [['tag' => 'a42', 'type' => 'asset']], + [['tag' => 'a5', 'type' => 'asset']], $dataCollector->getTags(), ); } @@ -124,7 +124,7 @@ public function collect_tags_of_type_asset(): void #[ConfigureRoute(__DIR__ . '/../Fixtures/get_object_route.php')] public function collect_tags_of_type_custom(): void { - self::arrange(fn () => TestObjectFactory::simpleObject()->save()); + self::arrange(fn () => TestObjectFactory::simpleObject(5)->save()); self::getContainer()->get('event_dispatcher')->addListener( ElementTaggingEvent::class, @@ -133,7 +133,7 @@ public function collect_tags_of_type_custom(): void ), ); - $this->client->request('GET', '/get-object?id=42'); + $this->client->request('GET', '/get-object?id=5'); $this->client->enableProfiler(); $dataCollector = $this->client->getProfile()->getCollector('pimcore_http_cache'); @@ -156,9 +156,9 @@ public function collect_tags_of_type_custom(): void #[ConfigureRoute(__DIR__ . '/../Fixtures/get_object_route.php')] public function does_not_collect_tags_when_type_is_disabled(): void { - self::arrange(fn () => TestObjectFactory::simpleObject()->save()); + self::arrange(fn () => TestObjectFactory::simpleObject(5)->save()); - $this->client->request('GET', '/get-object?id=42'); + $this->client->request('GET', '/get-object?id=5'); $this->client->enableProfiler(); $dataCollector = $this->client->getProfile()->getCollector('pimcore_http_cache'); @@ -178,10 +178,10 @@ public function does_not_collect_tags_when_type_is_disabled(): void #[ConfigureRoute(__DIR__ . '/../Fixtures/get_object_route.php')] public function does_not_collect_tags_when_caching_is_disabled(): void { - self::arrange(fn () => TestObjectFactory::simpleObject()->save()); + self::arrange(fn () => TestObjectFactory::simpleObject(5)->save()); self::getContainer()->get(CacheActivator::class)->deactivateCaching(); - $this->client->request('GET', '/get-object?id=42'); + $this->client->request('GET', '/get-object?id=5'); $this->client->enableProfiler(); $dataCollector = $this->client->getProfile()->getCollector('pimcore_http_cache'); @@ -206,9 +206,9 @@ public function does_not_collect_tags_when_caching_is_disabled(): void #[ConfigureRoute(__DIR__ . '/../Fixtures/get_object_route.php')] public function does_not_collect_tags_when_object_type_is_disabled(): void { - self::arrange(fn () => TestObjectFactory::simpleVariant()->save()); + self::arrange(fn () => TestObjectFactory::simpleVariant(5)->save()); - $this->client->request('GET', '/get-object?id=42'); + $this->client->request('GET', '/get-object?id=5'); $this->client->enableProfiler(); $dataCollector = $this->client->getProfile()->getCollector('pimcore_http_cache'); @@ -224,7 +224,7 @@ public function does_not_collect_tags_when_object_type_is_disabled(): void 'elements' => [ 'objects' => [ 'classes' => [ - 'TestDataObject' => false, + 'TestObject' => false, ], 'enabled' => true, ], @@ -233,9 +233,9 @@ public function does_not_collect_tags_when_object_type_is_disabled(): void #[ConfigureRoute(__DIR__ . '/../Fixtures/get_object_route.php')] public function does_not_collect_tags_when_object_class_is_disabled(): void { - self::arrange(fn () => TestObjectFactory::simpleObject()->save()); + self::arrange(fn () => TestObjectFactory::simpleObject(5)->save()); - $this->client->request('GET', '/get-object?id=42'); + $this->client->request('GET', '/get-object?id=5'); $this->client->enableProfiler(); $dataCollector = $this->client->getProfile()->getCollector('pimcore_http_cache'); @@ -261,9 +261,9 @@ public function does_not_collect_tags_when_object_class_is_disabled(): void #[ConfigureRoute(__DIR__ . '/../Fixtures/get_object_route.php')] public function does_not_collect_tags_when_profiler_is_disabled(): void { - self::arrange(fn () => TestObjectFactory::simpleObject()->save()); + self::arrange(fn () => TestObjectFactory::simpleObject(5)->save()); - $this->client->request('GET', '/get-object?id=42'); + $this->client->request('GET', '/get-object?id=5'); $this->client->enableProfiler(); self::assertFalse($this->client->getProfile()); @@ -278,9 +278,9 @@ public function does_not_collect_tags_when_profiler_is_disabled(): void #[ConfigureRoute(__DIR__ . '/../Fixtures/get_object_route.php')] public function does_not_collect_tags_when_collect_is_disabled(): void { - self::arrange(fn () => TestObjectFactory::simpleObject()->save()); + self::arrange(fn () => TestObjectFactory::simpleObject(5)->save()); - $this->client->request('GET', '/get-object?id=42'); + $this->client->request('GET', '/get-object?id=5'); $this->client->enableProfiler(); $dataCollector = $this->client->getProfile()->getCollector('pimcore_http_cache'); diff --git a/tests/Integration/Tagging/TagAdditionalTagTest.php b/tests/Integration/Tagging/TagAdditionalTagTest.php index 5abf34f..7c14bf8 100644 --- a/tests/Integration/Tagging/TagAdditionalTagTest.php +++ b/tests/Integration/Tagging/TagAdditionalTagTest.php @@ -44,24 +44,24 @@ protected function setUp(): void ])] public function response_is_tagged_with_additional_tag_when_asset_is_loaded(): void { - self::arrange(fn () => TestAssetFactory::simpleAsset()->save()); - self::arrange(fn () => TestAssetFactory::simpleImage()->save()); + self::arrange(fn () => TestAssetFactory::simpleAsset(5)->save()); + self::arrange(fn () => TestAssetFactory::simpleImage(29)->save()); self::getContainer()->get('event_dispatcher')->addListener( ElementTaggingEvent::class, fn (ElementTaggingEvent $event) => $event->addTag( - CacheTag::fromString('17', new ElementCacheType(ElementType::Asset)), + CacheTag::fromString('29', new ElementCacheType(ElementType::Asset)), ), ); - $this->client->request('GET', '/get-asset?id=42'); + $this->client->request('GET', '/get-asset?id=5'); $response = $this->client->getResponse(); self::assertSame('This is the content of the test asset.', $response->getContent()); self::assertSame(200, $response->getStatusCode()); self::assertTrue($response->headers->getCacheControlDirective('public')); self::assertSame('3600', $response->headers->getCacheControlDirective('s-maxage')); - self::assertStringContainsString('a17', $response->headers->get('X-Cache-Tags')); + self::assertStringContainsString('a29', $response->headers->get('X-Cache-Tags')); } /** @@ -74,13 +74,13 @@ public function response_is_tagged_with_additional_tag_when_asset_is_loaded(): v ])] public function response_is_tagged_with_additional_tag_when_document_is_loaded(): void { - self::arrange(fn () => TestDocumentFactory::simplePage()->save()); - self::arrange(fn () => TestDocumentFactory::simpleSnippet()->save()); + self::arrange(fn () => TestDocumentFactory::simplePage(5)->save()); + self::arrange(fn () => TestDocumentFactory::simpleSnippet(12)->save()); self::getContainer()->get('event_dispatcher')->addListener( ElementTaggingEvent::class, fn (ElementTaggingEvent $event) => $event->addTag( - CacheTag::fromString('23', new ElementCacheType(ElementType::Document)), + CacheTag::fromString('12', new ElementCacheType(ElementType::Document)), ), ); @@ -91,7 +91,7 @@ public function response_is_tagged_with_additional_tag_when_document_is_loaded() self::assertSame(200, $response->getStatusCode()); self::assertTrue($response->headers->getCacheControlDirective('public')); self::assertSame('3600', $response->headers->getCacheControlDirective('s-maxage')); - self::assertStringContainsString('d23', $response->headers->get('X-Cache-Tags')); + self::assertStringContainsString('d12', $response->headers->get('X-Cache-Tags')); } /** @@ -104,24 +104,24 @@ public function response_is_tagged_with_additional_tag_when_document_is_loaded() ])] public function response_is_tagged_with_additional_tag_when_object_is_loaded(): void { - self::arrange(fn () => TestObjectFactory::simpleObject()->save()); - self::arrange(fn () => TestObjectFactory::simpleVariant()->save()); + self::arrange(fn () => TestObjectFactory::simpleObject(5)->save()); + self::arrange(fn () => TestObjectFactory::simpleVariant(12)->save()); self::getContainer()->get('event_dispatcher')->addListener( ElementTaggingEvent::class, fn (ElementTaggingEvent $event) => $event->addTag( - CacheTag::fromString('17', new ElementCacheType(ElementType::Object)), + CacheTag::fromString('12', new ElementCacheType(ElementType::Object)), ), ); - $this->client->request('GET', '/get-object?id=42'); + $this->client->request('GET', '/get-object?id=5'); $response = $this->client->getResponse(); self::assertSame('Test content', $response->getContent()); self::assertSame(200, $response->getStatusCode()); self::assertTrue($response->headers->getCacheControlDirective('public')); self::assertSame('3600', $response->headers->getCacheControlDirective('s-maxage')); - self::assertStringContainsString('o17', $response->headers->get('X-Cache-Tags')); + self::assertStringContainsString('o5', $response->headers->get('X-Cache-Tags')); } /** @@ -137,7 +137,7 @@ public function response_is_tagged_with_additional_tag_when_object_is_loaded(): ])] public function response_is_tagged_with_custom_tag_when_element_is_loaded(): void { - self::arrange(fn () => TestObjectFactory::simpleObject()->save()); + self::arrange(fn () => TestObjectFactory::simpleObject(5)->save()); self::getContainer()->get('event_dispatcher')->addListener( ElementTaggingEvent::class, @@ -146,7 +146,7 @@ public function response_is_tagged_with_custom_tag_when_element_is_loaded(): voi ), ); - $this->client->request('GET', '/get-object?id=42'); + $this->client->request('GET', '/get-object?id=5'); $response = $this->client->getResponse(); self::assertSame('Test content', $response->getContent()); diff --git a/tests/Integration/Tagging/TagAssetTest.php b/tests/Integration/Tagging/TagAssetTest.php index d1aa49a..b036434 100644 --- a/tests/Integration/Tagging/TagAssetTest.php +++ b/tests/Integration/Tagging/TagAssetTest.php @@ -34,16 +34,16 @@ protected function setUp(): void ])] public function response_is_tagged_with_expected_tags_when_asset_is_loaded(): void { - self::arrange(fn () => TestAssetFactory::simpleAsset()->save()); + self::arrange(fn () => TestAssetFactory::simpleAsset(5)->save()); - $this->client->request('GET', '/get-asset?id=42'); + $this->client->request('GET', '/get-asset?id=5'); $response = $this->client->getResponse(); self::assertSame('This is the content of the test asset.', $response->getContent()); self::assertSame(200, $response->getStatusCode()); self::assertTrue($response->headers->getCacheControlDirective('public')); self::assertSame('3600', $response->headers->getCacheControlDirective('s-maxage')); - self::assertSame('a42', $response->headers->get('X-Cache-Tags')); + self::assertSame('a5', $response->headers->get('X-Cache-Tags')); } /** @@ -56,9 +56,9 @@ public function response_is_tagged_with_expected_tags_when_asset_is_loaded(): vo ])] public function response_is_not_tagged_when_assets_is_not_enabled(): void { - self::arrange(fn () => TestAssetFactory::simpleAsset()->save()); + self::arrange(fn () => TestAssetFactory::simpleAsset(5)->save()); - $this->client->request('GET', '/get-asset?id=42'); + $this->client->request('GET', '/get-asset?id=5'); $response = $this->client->getResponse(); self::assertSame('This is the content of the test asset.', $response->getContent()); @@ -78,10 +78,10 @@ public function response_is_not_tagged_when_assets_is_not_enabled(): void ])] public function response_is_not_tagged_when_caching_is_deactivated(): void { - self::arrange(fn () => TestAssetFactory::simpleAsset()->save()); + self::arrange(fn () => TestAssetFactory::simpleAsset(5)->save()); self::getContainer()->get(CacheActivator::class)->deactivateCaching(); - $this->client->request('GET', '/get-asset?id=42'); + $this->client->request('GET', '/get-asset?id=5'); $response = $this->client->getResponse(); self::assertSame('This is the content of the test asset.', $response->getContent()); @@ -101,9 +101,9 @@ public function response_is_not_tagged_when_caching_is_deactivated(): void ])] public function response_is_not_tagged_when_asset_is_of_type_folder(): void { - self::arrange(fn () => TestAssetFactory::simpleFolder()->save()); + self::arrange(fn () => TestAssetFactory::simpleFolder(12)->save()); - $this->client->request('GET', '/get-asset?id=23'); + $this->client->request('GET', '/get-asset?id=12'); $response = $this->client->getResponse(); self::assertSame('', $response->getContent()); @@ -128,9 +128,9 @@ public function response_is_not_tagged_when_asset_is_of_type_folder(): void ])] public function response_is_not_tagged_for_specified_asset_type(): void { - self::arrange(fn () => TestAssetFactory::simpleImage()->save()); + self::arrange(fn () => TestAssetFactory::simpleImage(29)->save()); - $this->client->request('GET', '/get-asset?id=17'); + $this->client->request('GET', '/get-asset?id=29'); $response = $this->client->getResponse(); self::assertSame('', $response->getContent()); diff --git a/tests/Integration/Tagging/TagDocumentTest.php b/tests/Integration/Tagging/TagDocumentTest.php index e6b1fd3..66efe47 100644 --- a/tests/Integration/Tagging/TagDocumentTest.php +++ b/tests/Integration/Tagging/TagDocumentTest.php @@ -34,7 +34,7 @@ protected function setUp(): void ])] public function response_is_tagged_with_expected_tags_when_page_is_loaded(): void { - self::arrange(fn () => TestDocumentFactory::simplePage()->save()); + self::arrange(fn () => TestDocumentFactory::simplePage(5)->save()); $this->client->request('GET', '/test_document_page'); @@ -43,7 +43,7 @@ public function response_is_tagged_with_expected_tags_when_page_is_loaded(): voi self::assertSame(200, $response->getStatusCode()); self::assertTrue($response->headers->getCacheControlDirective('public')); self::assertSame('3600', $response->headers->getCacheControlDirective('s-maxage')); - self::assertStringContainsString('d42', $response->headers->get('X-Cache-Tags')); + self::assertStringContainsString('d5', $response->headers->get('X-Cache-Tags')); } /** @@ -56,16 +56,16 @@ public function response_is_tagged_with_expected_tags_when_page_is_loaded(): voi ])] public function response_is_tagged_with_expected_tags_when_snippet_is_loaded(): void { - self::arrange(fn () => TestDocumentFactory::simpleSnippet()->save()); + self::arrange(fn () => TestDocumentFactory::simpleSnippet(12)->save()); - $this->client->request('GET', '/get-document?id=23'); + $this->client->request('GET', '/get-document?id=12'); $response = $this->client->getResponse(); self::assertSame('Document with key: test_document_snippet', $response->getContent()); self::assertSame(200, $response->getStatusCode()); self::assertTrue($response->headers->getCacheControlDirective('public')); self::assertSame('3600', $response->headers->getCacheControlDirective('s-maxage')); - self::assertStringContainsString('d23', $response->headers->get('X-Cache-Tags')); + self::assertStringContainsString('d12', $response->headers->get('X-Cache-Tags')); } /** @@ -78,16 +78,16 @@ public function response_is_tagged_with_expected_tags_when_snippet_is_loaded(): ])] public function response_is_not_tagged_when_document_type_is_email(): void { - self::arrange(fn () => TestDocumentFactory::simpleEmail()->save()); + self::arrange(fn () => TestDocumentFactory::simpleEmail(29)->save()); - $this->client->request('GET', '/get-document?id=17'); + $this->client->request('GET', '/get-document?id=29'); $response = $this->client->getResponse(); - self::assertSame('Document with key: test_document_link', $response->getContent()); + self::assertSame('Document with key: test_document_email', $response->getContent()); self::assertSame(200, $response->getStatusCode()); self::assertTrue($response->headers->getCacheControlDirective('public')); self::assertSame('3600', $response->headers->getCacheControlDirective('s-maxage')); - self::assertStringNotContainsString('d17', $response->headers->get('X-Cache-Tags')); + self::assertStringNotContainsString('d29', $response->headers->get('X-Cache-Tags')); } /** @@ -100,16 +100,16 @@ public function response_is_not_tagged_when_document_type_is_email(): void ])] public function response_is_not_tagged_when_document_type_is_hard_link(): void { - self::arrange(fn () => TestDocumentFactory::simpleHardLink()->save()); + self::arrange(fn () => TestDocumentFactory::simpleHardLink(12)->save()); - $this->client->request('GET', '/get-document?id=33'); + $this->client->request('GET', '/get-document?id=12'); $response = $this->client->getResponse(); self::assertSame('Document with key: test_document_hard_link', $response->getContent()); self::assertSame(200, $response->getStatusCode()); self::assertTrue($response->headers->getCacheControlDirective('public')); self::assertSame('3600', $response->headers->getCacheControlDirective('s-maxage')); - self::assertStringNotContainsString('d33', $response->headers->get('X-Cache-Tags')); + self::assertStringNotContainsString('d29', $response->headers->get('X-Cache-Tags')); } /** @@ -122,16 +122,16 @@ public function response_is_not_tagged_when_document_type_is_hard_link(): void ])] public function response_is_not_tagged_when_document_type_is_folder(): void { - self::arrange(fn () => TestDocumentFactory::simpleFolder()->save()); + self::arrange(fn () => TestDocumentFactory::simpleFolder(70)->save()); - $this->client->request('GET', '/get-document?id=97'); + $this->client->request('GET', '/get-document?id=70'); $response = $this->client->getResponse(); self::assertSame('Document with key: test_document_folder', $response->getContent()); self::assertSame(200, $response->getStatusCode()); self::assertTrue($response->headers->getCacheControlDirective('public')); self::assertSame('3600', $response->headers->getCacheControlDirective('s-maxage')); - self::assertStringNotContainsString('d97', $response->headers->get('X-Cache-Tags')); + self::assertStringNotContainsString('d70', $response->headers->get('X-Cache-Tags')); } /** @@ -144,7 +144,7 @@ public function response_is_not_tagged_when_document_type_is_folder(): void ])] public function response_is_not_tagged_when_documents_is_not_enabled(): void { - self::arrange(fn () => TestDocumentFactory::simplePage()->save()); + self::arrange(fn () => TestDocumentFactory::simplePage(5)->save()); $this->client->request('GET', '/test_document_page'); @@ -166,7 +166,7 @@ public function response_is_not_tagged_when_documents_is_not_enabled(): void ])] public function response_is_not_tagged_when_caching_is_deactivated(): void { - self::arrange(fn () => TestDocumentFactory::simplePage()->save()); + self::arrange(fn () => TestDocumentFactory::simplePage(5)->save()); self::getContainer()->get(CacheActivator::class)->deactivateCaching(); $this->client->request('GET', '/test_document_page'); @@ -189,7 +189,7 @@ public function response_is_not_tagged_when_caching_is_deactivated(): void ])] public function response_is_tagged_with_root_document_tag_when_loaded(): void { - self::arrange(fn () => TestDocumentFactory::simplePage()->save()); + self::arrange(fn () => TestDocumentFactory::simplePage(5)->save()); $this->client->request('GET', '/test_document_page'); @@ -215,7 +215,7 @@ public function response_is_tagged_with_root_document_tag_when_loaded(): void ])] public function response_is_not_tagged_when_type_is_disabled(): void { - self::arrange(fn () => TestDocumentFactory::simplePage()->save()); + self::arrange(fn () => TestDocumentFactory::simplePage(5)->save()); $this->client->request('GET', '/test_document_page'); diff --git a/tests/Integration/Tagging/TagObjectTest.php b/tests/Integration/Tagging/TagObjectTest.php index a502917..7386464 100644 --- a/tests/Integration/Tagging/TagObjectTest.php +++ b/tests/Integration/Tagging/TagObjectTest.php @@ -34,16 +34,16 @@ protected function setUp(): void ])] public function response_is_tagged_with_expected_tags_when_object_is_loaded(): void { - self::arrange(fn () => TestObjectFactory::simpleObject()->save()); + self::arrange(fn () => TestObjectFactory::simpleObject(5)->save()); - $this->client->request('GET', '/get-object?id=42'); + $this->client->request('GET', '/get-object?id=5'); $response = $this->client->getResponse(); self::assertSame('Test content', $response->getContent()); self::assertSame(200, $response->getStatusCode()); self::assertTrue($response->headers->getCacheControlDirective('public')); self::assertSame('3600', $response->headers->getCacheControlDirective('s-maxage')); - self::assertSame('o42', $response->headers->get('X-Cache-Tags')); + self::assertSame('o5', $response->headers->get('X-Cache-Tags')); } /** @@ -56,9 +56,9 @@ public function response_is_tagged_with_expected_tags_when_object_is_loaded(): v ])] public function response_is_not_tagged_when_objects_is_not_enabled(): void { - self::arrange(fn () => TestObjectFactory::simpleObject()->save()); + self::arrange(fn () => TestObjectFactory::simpleObject(5)->save()); - $this->client->request('GET', '/get-object?id=42'); + $this->client->request('GET', '/get-object?id=5'); $response = $this->client->getResponse(); self::assertSame('Test content', $response->getContent()); @@ -78,10 +78,10 @@ public function response_is_not_tagged_when_objects_is_not_enabled(): void ])] public function response_is_not_tagged_when_caching_is_deactivated(): void { - self::arrange(fn () => TestObjectFactory::simpleObject()->save()); + self::arrange(fn () => TestObjectFactory::simpleObject(5)->save()); self::getContainer()->get(CacheActivator::class)->deactivateCaching(); - $this->client->request('GET', '/get-object?id=42'); + $this->client->request('GET', '/get-object?id=5'); $response = $this->client->getResponse(); self::assertSame('Test content', $response->getContent()); @@ -106,9 +106,9 @@ public function response_is_not_tagged_when_caching_is_deactivated(): void ])] public function response_is_not_tagged_when_object_type_is_disabled(): void { - self::arrange(fn () => TestObjectFactory::simpleVariant()->save()); + self::arrange(fn () => TestObjectFactory::simpleVariant(5)->save()); - $this->client->request('GET', '/get-object?id=17'); + $this->client->request('GET', '/get-object?id=5'); $response = $this->client->getResponse(); self::assertSame('Test content', $response->getContent()); @@ -133,16 +133,16 @@ public function response_is_not_tagged_when_object_type_is_disabled(): void ])] public function response_ist_tagged_when_object_type_is_enabled(): void { - self::arrange(fn () => TestObjectFactory::simpleVariant()->save()); + self::arrange(fn () => TestObjectFactory::simpleVariant(12)->save()); - $this->client->request('GET', '/get-object?id=17'); + $this->client->request('GET', '/get-object?id=12'); $response = $this->client->getResponse(); self::assertSame('Test content', $response->getContent()); self::assertSame(200, $response->getStatusCode()); self::assertTrue($response->headers->getCacheControlDirective('public')); self::assertSame('3600', $response->headers->getCacheControlDirective('s-maxage')); - self::assertSame('o17', $response->headers->get('X-Cache-Tags')); + self::assertSame('o12', $response->headers->get('X-Cache-Tags')); } /** @@ -152,7 +152,7 @@ public function response_ist_tagged_when_object_type_is_enabled(): void 'elements' => [ 'objects' => [ 'classes' => [ - 'TestDataObject' => false, + 'TestObject' => false, ], 'enabled' => true, ], @@ -160,9 +160,9 @@ public function response_ist_tagged_when_object_type_is_enabled(): void ])] public function response_is_not_tagged_when_object_class_is_disabled(): void { - self::arrange(fn () => TestObjectFactory::simpleObject()->save()); + self::arrange(fn () => TestObjectFactory::simpleObject(5)->save()); - $this->client->request('GET', '/get-object?id=42'); + $this->client->request('GET', '/get-object?id=5'); $response = $this->client->getResponse(); self::assertSame('Test content', $response->getContent()); @@ -179,7 +179,7 @@ public function response_is_not_tagged_when_object_class_is_disabled(): void 'elements' => [ 'objects' => [ 'classes' => [ - 'TestDataObject' => true, + 'TestObject' => true, ], 'enabled' => true, ], @@ -187,15 +187,15 @@ public function response_is_not_tagged_when_object_class_is_disabled(): void ])] public function response_is_tagged_when_object_class_is_enabled(): void { - self::arrange(fn () => TestObjectFactory::simpleObject()->save()); + self::arrange(fn () => TestObjectFactory::simpleObject(5)->save()); - $this->client->request('GET', '/get-object?id=42'); + $this->client->request('GET', '/get-object?id=5'); $response = $this->client->getResponse(); self::assertSame('Test content', $response->getContent()); self::assertSame(200, $response->getStatusCode()); self::assertTrue($response->headers->getCacheControlDirective('public')); self::assertSame('3600', $response->headers->getCacheControlDirective('s-maxage')); - self::assertSame('o42', $response->headers->get('X-Cache-Tags')); + self::assertSame('o5', $response->headers->get('X-Cache-Tags')); } } diff --git a/tests/Unit/Element/InvalidateElementListenerTest.php b/tests/Unit/Element/InvalidateElementListenerTest.php index 21d541b..5acf14c 100644 --- a/tests/Unit/Element/InvalidateElementListenerTest.php +++ b/tests/Unit/Element/InvalidateElementListenerTest.php @@ -6,6 +6,8 @@ use Neusta\Pimcore\HttpCacheBundle\Cache\CacheTag; use Neusta\Pimcore\HttpCacheBundle\Cache\CacheTags; use Neusta\Pimcore\HttpCacheBundle\Element\ElementInvalidationEvent; +use Neusta\Pimcore\HttpCacheBundle\Element\ElementRepository; +use Neusta\Pimcore\HttpCacheBundle\Element\ElementType; use Neusta\Pimcore\HttpCacheBundle\Element\InvalidateElementListener; use PHPUnit\Framework\TestCase; use Pimcore\Event\Model\AssetEvent; @@ -14,6 +16,7 @@ use Pimcore\Event\Model\ElementEventInterface; use Pimcore\Model\Asset; use Pimcore\Model\DataObject; +use Pimcore\Model\Dependency; use Pimcore\Model\Document; use Prophecy\Argument; use Prophecy\PhpUnit\ProphecyTrait; @@ -32,13 +35,18 @@ final class InvalidateElementListenerTest extends TestCase /** @var ObjectProphecy */ private $eventDispatcher; + /** @var ObjectProphecy */ + private $elementRepository; + protected function setUp(): void { $this->cacheInvalidator = $this->prophesize(CacheInvalidator::class); $this->eventDispatcher = $this->prophesize(EventDispatcherInterface::class); + $this->elementRepository = $this->prophesize(ElementRepository::class); $this->invalidateElementListener = new InvalidateElementListener( $this->cacheInvalidator->reveal(), $this->eventDispatcher->reveal(), + $this->elementRepository->reveal(), ); $this->eventDispatcher->dispatch(Argument::type(ElementInvalidationEvent::class)) @@ -105,6 +113,64 @@ public function onUpdate_should_invalidate_elements(ElementEventInterface $event ->shouldHaveBeenCalledOnce(); } + /** + * @test + */ + public function onUpdate_should_invalidate_dependencies(): void + { + $element = $this->prophesize(DataObject\TestObject::class); + $element->getType()->willReturn(ElementType::Object->value); + $dependency = $this->prophesize(Dependency::class); + $dependentElement = $this->prophesize(DataObject::class); + $event = new DataObjectEvent($element->reveal()); + + $element->getId()->willReturn(42); + $element->getDependencies()->willReturn($dependency->reveal()); + $dependentElement->getId()->willReturn(23); + $dependency->getRequiredBy()->willReturn([['id' => 23, 'type' => 'object']]); + $this->elementRepository->findObject(23)->willReturn($dependentElement->reveal()); + + $this->invalidateElementListener->onUpdate($event); + + $this->cacheInvalidator->invalidate(Argument::which('toString', CacheTag::fromElement($dependentElement->reveal())->toString())) + ->shouldHaveBeenCalledOnce(); + } + + /** + * @test + * + * @dataProvider notObjectElementProvider + */ + public function onUpdate_should_not_invalidate_dependencies_when_element_is_not_an_object( + ElementEventInterface $event, + ): void { + $this->invalidateElementListener->onUpdate($event); + + $this->cacheInvalidator->invalidate(Argument::any()) + ->shouldHaveBeenCalledOnce(); + $this->elementRepository->findObject(Argument::any()) + ->shouldNotHaveBeenCalled(); + } + + public function notObjectElementProvider(): iterable + { + $asset = $this->prophesize(Asset::class); + $dependency = $this->prophesize(Dependency::class); + $asset->getId()->willReturn(42); + $asset->getType()->willReturn(ElementType::Asset->value); + $asset->getDependencies()->willReturn($dependency->reveal()); + $dependency->getRequiredBy()->willReturn(['id' => 23, 'type' => 'object']); + yield 'Asset' => ['event' => new AssetEvent($asset->reveal())]; + + $document = $this->prophesize(Document::class); + $dependency = $this->prophesize(Dependency::class); + $document->getId()->willReturn(42); + $document->getType()->willReturn(ElementType::Document->value); + $document->getDependencies()->willReturn($dependency->reveal()); + $dependency->getRequiredBy()->willReturn(['id' => 23, 'type' => 'object']); + yield 'Document' => ['event' => new DocumentEvent($document->reveal())]; + } + /** * @test * @@ -177,6 +243,29 @@ public function onDelete_should_invalidate_elements(ElementEventInterface $event ->shouldHaveBeenCalledOnce(); } + /** + * @test + */ + public function onDelete_should_invalidate_dependent_elements(): void + { + $element = $this->prophesize(DataObject\TestObject::class); + $element->getType()->willReturn(ElementType::Object->value); + $dependency = $this->prophesize(Dependency::class); + $dependentElement = $this->prophesize(DataObject::class); + $event = new DataObjectEvent($element->reveal()); + + $element->getId()->willReturn(42); + $element->getDependencies()->willReturn($dependency->reveal()); + $dependentElement->getId()->willReturn(23); + $dependency->getRequiredBy()->willReturn([['id' => 23, 'type' => 'object']]); + $this->elementRepository->findObject(23)->willReturn($dependentElement->reveal()); + + $this->invalidateElementListener->onDelete($event); + + $this->cacheInvalidator->invalidate(Argument::which('toString', CacheTag::fromElement($dependentElement->reveal())->toString())) + ->shouldHaveBeenCalledOnce(); + } + /** * @test * @@ -223,16 +312,25 @@ public function onDelete_should_invalidate_additional_tags_when_requested(Elemen public function elementProvider(): iterable { + $dependency = $this->prophesize(Dependency::class); + $asset = $this->prophesize(Asset::class); $asset->getId()->willReturn(42); + $asset->getDependencies()->willReturn($dependency->reveal()); + $asset->getType()->willReturn(ElementType::Asset->value); yield 'Asset' => ['event' => new AssetEvent($asset->reveal())]; $document = $this->prophesize(Document::class); $document->getId()->willReturn(42); + $document->getDependencies()->willReturn($dependency->reveal()); + $document->getType()->willReturn(ElementType::Document->value); yield 'Document' => ['event' => new DocumentEvent($document->reveal())]; $dataObject = $this->prophesize(DataObject::class); $dataObject->getId()->willReturn(42); + $dataObject->getDependencies()->willReturn($dependency->reveal()); + $dependency->getRequiredBy()->willReturn([]); + $dataObject->getType()->willReturn(ElementType::Object->value); yield 'Object' => ['event' => new DataObjectEvent($dataObject->reveal())]; } } diff --git a/tests/app/config/pimcore/classes/definition_TestDataObject.php b/tests/app/config/pimcore/classes/definition_TestObject.php similarity index 62% rename from tests/app/config/pimcore/classes/definition_TestDataObject.php rename to tests/app/config/pimcore/classes/definition_TestObject.php index c7ed3b8..f556bc9 100644 --- a/tests/app/config/pimcore/classes/definition_TestDataObject.php +++ b/tests/app/config/pimcore/classes/definition_TestObject.php @@ -1,14 +1,23 @@ null, - 'id' => 'test_data_object', - 'name' => 'TestDataObject', + 'id' => 'test_object', + 'name' => 'TestObject', 'description' => '', 'creationDate' => 0, - 'modificationDate' => 1685448671, - 'userOwner' => 1, - 'userModification' => 1, + 'modificationDate' => 1755079708, + 'userOwner' => 58, + 'userModification' => 58, 'parentClass' => '', 'implementsInterfaces' => '', 'listingParentClass' => '', @@ -40,8 +49,8 @@ 'type' => null, 'region' => null, 'title' => '', - 'width' => null, - 'height' => null, + 'width' => '', + 'height' => '', 'collapsible' => false, 'collapsed' => false, 'bodyStyle' => '', @@ -52,7 +61,7 @@ 'name' => 'content', 'title' => 'Content', 'tooltip' => '', - 'mandatory' => true, + 'mandatory' => false, 'noteditable' => false, 'index' => false, 'locked' => false, @@ -66,7 +75,7 @@ 'visibleSearch' => false, 'blockedVarsForExport' => [ ], - 'width' => null, + 'width' => '', 'defaultValue' => null, 'columnLength' => 190, 'regex' => '', @@ -76,6 +85,49 @@ 'showCharCount' => false, 'defaultValueGenerator' => '', ]), + 1 => Pimcore\Model\DataObject\ClassDefinition\Data\ManyToManyRelation::__set_state([ + 'name' => 'related', + 'title' => 'Related', + 'tooltip' => '', + 'mandatory' => false, + 'noteditable' => false, + 'index' => false, + 'locked' => false, + 'style' => '', + 'permissions' => null, + 'datatype' => 'data', + 'fieldtype' => 'manyToManyRelation', + 'relationType' => true, + 'invisible' => false, + 'visibleGridView' => false, + 'visibleSearch' => false, + 'blockedVarsForExport' => [ + ], + 'classes' => [ + 0 => [ + 'classes' => 'TestObject', + ], + ], + 'pathFormatterClass' => '', + 'width' => '', + 'height' => '', + 'maxItems' => null, + 'assetUploadPath' => '', + 'objectsAllowed' => true, + 'assetsAllowed' => true, + 'assetTypes' => [ + 0 => [ + 'assetTypes' => 'image', + ], + ], + 'documentsAllowed' => true, + 'documentTypes' => [ + 0 => [ + 'documentTypes' => 'page', + ], + ], + 'enableTextSelection' => false, + ]), ], 'locked' => false, 'blockedVarsForExport' => [ @@ -83,8 +135,8 @@ 'fieldtype' => 'panel', 'layout' => null, 'border' => false, - 'icon' => null, - 'labelWidth' => 100, + 'icon' => '', + 'labelWidth' => 0, 'labelAlign' => 'left', ]), ], diff --git a/tests/app/src/Controller/GetObjectController.php b/tests/app/src/Controller/GetObjectController.php index fd69901..31443a1 100644 --- a/tests/app/src/Controller/GetObjectController.php +++ b/tests/app/src/Controller/GetObjectController.php @@ -2,7 +2,7 @@ namespace App\Controller; -use Pimcore\Model\DataObject\TestDataObject; +use Pimcore\Model\DataObject\TestObject; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; @@ -10,7 +10,7 @@ final class GetObjectController { public function __invoke(Request $request): Response { - if (!$object = TestDataObject::getById($request->query->get('id'))) { + if (!$object = TestObject::getById($request->query->get('id'))) { return new Response('Object not found', Response::HTTP_NOT_FOUND); }