{"action":"created","issue":{"url":"https://api.github.com/repos/ezsystems/ezpublish-kernel/issues/1772","repository_url":"https://api.github.com/repos/ezsystems/ezpublish-kernel","labels_url":"https://api.github.com/repos/ezsystems/ezpublish-kernel/issues/1772/labels{/name}","comments_url":"https://api.github.com/repos/ezsystems/ezpublish-kernel/issues/1772/comments","events_url":"https://api.github.com/repos/ezsystems/ezpublish-kernel/issues/1772/events","html_url":"https://github.com/ezsystems/ezpublish-kernel/pull/1772","id":175784131,"number":1772,"title":"[WIP] Feature EZP-25696: HTTPCache Multi Tagging/labeling","user":{"login":"andrerom","id":289757,"avatar_url":"https://avatars.githubusercontent.com/u/289757?v=3","gravatar_id":"","url":"https://api.github.com/users/andrerom","html_url":"https://github.com/andrerom","followers_url":"https://api.github.com/users/andrerom/followers","following_url":"https://api.github.com/users/andrerom/following{/other_user}","gists_url":"https://api.github.com/users/andrerom/gists{/gist_id}","starred_url":"https://api.github.com/users/andrerom/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/andrerom/subscriptions","organizations_url":"https://api.github.com/users/andrerom/orgs","repos_url":"https://api.github.com/users/andrerom/repos","events_url":"https://api.github.com/users/andrerom/events{/privacy}","received_events_url":"https://api.github.com/users/andrerom/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":0,"created_at":"2016-09-08T15:25:08Z","updated_at":"2016-09-08T15:33:57Z","closed_at":null,"pull_request":{"url":"https://api.github.com/repos/ezsystems/ezpublish-kernel/pulls/1772","html_url":"https://github.com/ezsystems/ezpublish-kernel/pull/1772","diff_url":"https://github.com/ezsystems/ezpublish-kernel/pull/1772.diff","patch_url":"https://github.com/ezsystems/ezpublish-kernel/pull/1772.patch"},"body":"Epic: https://jira.ez.no/browse/EZP-25696\r\nAs we have own layers for HttpCache it is possible to solve this without waiting for others.\r\n\r\n### Solves:\r\n- Makes it possible to cache anything, example included is ContentType REST calls speeding up Platform UI _(but UI should cache these and not wait for server all the time in the first place)_\r\n- Solves lots of cache clearing issues, especially when deleting content\r\n- Makes it possible to combine several responses more reliably in one response  _(needed for [REST Embedding](https://github.com/ezsystems/ezpublish-kernel/pull/1741) to speed up Platform UI by reducing round trips on thins like content > main location and more importantly for [Permissions lookup REST API](https://github.com/ezsystems/ezpublish-kernel/pull/1730) to not greatly slow down UI further)_\r\n- Performance:\r\n - Less work on purge, no need to iterate the content tree to calculate what needs to be cleared\r\n - Better Varnish performance by move to xkey over Banning to allow stale purging (grace handling)\r\n - With this we can set default cache TTL much higher, as it more reliably clears relevant cache now _(there will be bugs, but they will be fixable now)_\r\n\r\n\r\n### BC\r\nThis change on purpose rather intrusive to HTTPCache layer, not all strictly needed to solve the issues, but overdue as it was somewhat jungle in there and cleanup highly needed as it has received changes over the years.\r\n- see doc/bc/changes-6.5.md\r\n- not mentioned yet, but as smart cache clearing won't come back in the form it current has the PR also deprecates and strips out use of `GatewayCachePurger` and implementations in favor of just the PurgeClientInterface layer.\r\n\r\n\r\n### Testing\r\n\r\nUsing eZ Platfomr 1.5 or master apply the following before running composer update and start server:\r\n```diff\r\ndiff --git a/app/config/ezplatform.yml b/app/config/ezplatform.yml\r\nindex edc4d2c..c411962 100644\r\n--- a/app/config/ezplatform.yml\r\n+++ b/app/config/ezplatform.yml\r\n@@ -29,3 +29,5 @@ ezpublish:\r\n             # so removing eng-GB from this list may lead to errors or content not being shown, unless you change\r\n             # all eng-GB data to other locales first.\r\n             languages: [eng-GB]\r\n+            content:\r\n+                default_ttl: 900\r\ndiff --git a/composer.json b/composer.json\r\nindex 25c2f42..6e6f510 100644\r\n--- a/composer.json\r\n+++ b/composer.json\r\n@@ -27,7 +27,7 @@\r\n         \"sensio/generator-bundle\": \"~2.3\",\r\n         \"incenteev/composer-parameter-handler\": \"~2.0\",\r\n         \"tedivm/stash-bundle\": \"~0.4\",\r\n-        \"ezsystems/ezpublish-kernel\": \"^6.5@dev\",\r\n+        \"ezsystems/ezpublish-kernel\": \"dev-feature-EZP-25696 as 6.5.2\",\r\n         \"ezsystems/repository-forms\": \"^1.4@dev\",\r\n         \"ezsystems/ezplatform-solr-search-engine\": \"^1.1@dev\",\r\n         \"ezsystems/platform-ui-bundle\": \"^1.5@dev\",\r\n```\r\n\r\n### Todo\r\n- VCL, two: of them for Varnish 4.x _(3.x not relevant anymore as 4.1 re-added VMOD support)_:\r\n - Varnish vanilla using BAN\r\n - Varnish using [xkey VMOD](https://github.com/varnish/varnish-modules/blob/master/docs/vmod_xkey.rst) as it is better performing then BAN and allows soft purge on the tags further enabling higher average performance. _NOTE: We will need to suggest use of different domain name for Platform UI with this, so Varnish can skip grace time for backend to avoid UI issues when loading stale data._\r\n- Fixes to `FOSPurgeClient` once VCL changes are in place to align\r\n\r\n### Future\r\n\r\n- Refactor TagAwareStore to just simply use Symfony Cache component once 3.2 is out to have more solid tag handling, and built in expiry support natively to reintroduce staleness _(however we need to look into how to avoid staleness for Platform UI requests as it will easily break the UI as mentioned in regards to Varnsih above)_\r\n"},"comment":{"url":"https://api.github.com/repos/ezsystems/ezpublish-kernel/issues/comments/245637876","html_url":"https://github.com/ezsystems/ezpublish-kernel/pull/1772#issuecomment-245637876","issue_url":"https://api.github.com/repos/ezsystems/ezpublish-kernel/issues/1772","id":245637876,"user":{"login":"ezrobot","id":681611,"avatar_url":"https://avatars.githubusercontent.com/u/681611?v=3","gravatar_id":"","url":"https://api.github.com/users/ezrobot","html_url":"https://github.com/ezrobot","followers_url":"https://api.github.com/users/ezrobot/followers","following_url":"https://api.github.com/users/ezrobot/following{/other_user}","gists_url":"https://api.github.com/users/ezrobot/gists{/gist_id}","starred_url":"https://api.github.com/users/ezrobot/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ezrobot/subscriptions","organizations_url":"https://api.github.com/users/ezrobot/orgs","repos_url":"https://api.github.com/users/ezrobot/repos","events_url":"https://api.github.com/users/ezrobot/events{/privacy}","received_events_url":"https://api.github.com/users/ezrobot/received_events","type":"User","site_admin":false},"created_at":"2016-09-08T15:33:57Z","updated_at":"2016-09-08T15:33:57Z","body":"This Pull Request does not respect [PSR-2 Coding Standards](http://www.php-fig.org/psr/psr-2/), please, see the suggested diff below:\n\n```diff\nLoaded config from \"/jenkins/jenkins.std/jobs/PAPI-Pull-Request-code-sniffer/workspace/.php_cs\"\n.........................................F........................................................................................................................................FFFFF.F.F..F.FFF.F.FF.....FFF..FFFF.FF..FFF.FF.FFFFFF...............................................................................F..................................................\nLegend: ?-unknown, I-invalid file syntax, file ignored, .-no changes, F-fixed, E-error\n   1) eZ/Bundle/EzPublishCoreBundle/EventListener/CacheViewResponseListener.php (function_declaration)\n      ---------- begin diff ----------\n      --- Original\n      +++ New\n      @@ @@\n                       ] + array_map(\n      -                    function($pathItem){\n      +                    function ($pathItem) {\n                               return 'path-' . $pathItem;\n                           },\n                           $location->path\n                       ),\n                       false\n                   );\n               }\n       \n               $response->setPublic();\n               if ($this->enableTtlCache && !$response->headers->hasCacheControlDirective('s-maxage')) {\n                   $response->setSharedMaxAge($this->defaultTtl);\n               }\n           }\n       }\n       \n      \n      ---------- end diff ----------\n\n   2) eZ/Publish/Core/MVC/Symfony/Cache/Tests/Http/TagAwareStoreTest.php (single_quote, concat_with_spaces)\n      ---------- begin diff ----------\n      --- Original\n      +++ New\n      @@ @@\n           {\n      -        $path = $this->store->getTagPath('location-123'). DIRECTORY_SEPARATOR . 'en' . sha1('someContent');\n      +        $path = $this->store->getTagPath('location-123') . DIRECTORY_SEPARATOR . 'en' . sha1('someContent');\n               $this->assertStringStartsWith(__DIR__ . DIRECTORY_SEPARATOR . 'ez/32/1-/noitacol', $path);\n           }\n       \n           public function testGetStalePath()\n           {\n      -        $this->markTestIncomplete(\"@todo Stale handling removed, needs adjustments once it is re added in new form\");\n      +        $this->markTestIncomplete('@todo Stale handling removed, needs adjustments once it is re added in new form');\n      \n      @@ @@\n           {\n      -        $this->markTestIncomplete(\"@todo Stale handling removed, needs adjustments once it is re added in new form\");\n      +        $this->markTestIncomplete('@todo Stale handling removed, needs adjustments once it is re added in new form');\n      \n      @@ @@\n           {\n      -        $this->markTestIncomplete(\"@todo needs adjustments for new impl on top of tags\");\n      +        $this->markTestIncomplete('@todo needs adjustments for new impl on top of tags');\n      \n      @@ @@\n           {\n      -        $this->markTestIncomplete(\"@todo needs adjustments for new impl on top of tags\");\n      +        $this->markTestIncomplete('@todo needs adjustments for new impl on top of tags');\n               $fs = $this->getFilesystemMock();\n               $this->store->setFilesystem($fs);\n               $locationIds = array(123, 456, 789);\n               $i = 0;\n               foreach ($locationIds as $locationId) {\n                   $locationCacheDir = $this->store->getTagPath('location-' . $locationId);\n                   $staleCacheDir = str_replace(TagAwareStore::TAG_CACHE_DIR, TagAwareStore::TAG_CACHE_DIR, $locationCacheDir);\n       \n                   $fs\n                       ->expects($this->at($i++))\n                       ->method('exists')\n                       ->with($locationCacheDir)\n                       ->will($this->returnValue(true));\n                   $fs\n                       ->expects($this->at($i++))\n                       ->method('mkdir')\n                       ->with($staleCacheDir);\n                   $fs\n                       ->expects($this->at($i++))\n                       ->method('mirror')\n                       ->with($locationCacheDir, $staleCacheDir);\n                   $fs\n                       ->expects($this->at($i++))\n                       ->method('remove')\n                       ->with($locationCacheDir);\n               }\n       \n               $request = Request::create('/', 'BAN');\n               $request->headers->set('X-Location-Id', '(' . implode('|', $locationIds) . ')');\n               $this->store->purgeByRequest($request);\n           }\n       \n           public function testPurgeAllContent()\n           {\n               $fs = $this->getFilesystemMock();\n               $this->store->setFilesystem($fs);\n               $locationCacheDir = $this->store->getTagPath();\n       \n               $fs\n                   ->expects($this->once())\n                   ->method('remove')\n                   ->with($locationCacheDir);\n       \n               $this->store->purgeAllContent();\n           }\n       \n           public function testPurgeAllContentByRequest()\n           {\n               $fs = $this->getFilesystemMock();\n               $this->store->setFilesystem($fs);\n               $locationCacheDir = $this->store->getTagPath();\n       \n               $fs\n                   ->expects($this->once())\n                   ->method('remove')\n                   ->with($locationCacheDir);\n       \n               $request = Request::create('/', 'BAN');\n               $request->headers->set('X-Location-Id', '.*');\n               $this->store->purgeByRequest($request);\n           }\n       \n           public function testPurgeAllContentByRequestBC()\n           {\n               $fs = $this->getFilesystemMock();\n               $this->store->setFilesystem($fs);\n               $locationCacheDir = $this->store->getTagPath();\n       \n               $fs\n                   ->expects($this->once())\n                   ->method('remove')\n                   ->with($locationCacheDir);\n       \n               $request = Request::create('/', 'PURGE');\n               $request->headers->set('X-Location-Id', '*');\n               $this->store->purgeByRequest($request);\n           }\n       }\n       \n      \n      ---------- end diff ----------\n\n   3) eZ/Publish/Core/MVC/Symfony/Cache/Tests/Http/SignalSlot/UnassignUserFromUserGroupSlotTest.php (concat_with_spaces)\n      ---------- begin diff ----------\n      --- Original\n      +++ New\n      @@ @@\n           {\n      -        return ['content-'.$this->contentId, 'content-99'];\n      +        return ['content-' . $this->contentId, 'content-99'];\n           }\n       \n           public function getSlotClass()\n           {\n               return 'eZ\\Publish\\Core\\MVC\\Symfony\\Cache\\Http\\SignalSlot\\UnassignUserFromUserGroupSlot';\n           }\n       \n           public function getReceivedSignalClasses()\n           {\n               return ['eZ\\Publish\\Core\\SignalSlot\\Signal\\UserService\\UnAssignUserFromUserGroupSignal'];\n           }\n       }\n       \n      \n      ---------- end diff ----------\n\n   4) eZ/Publish/Core/MVC/Symfony/Cache/Tests/Http/SignalSlot/RecoverSlotTest.php (multiline_array_trailing_comma, extra_empty_lines, concat_with_spaces)\n      ---------- begin diff ----------\n      --- Original\n      +++ New\n      @@ @@\n                       'newLocationId' => $this->locationId,\n      -                'newParentLocationId' => $this->parentLocationId\n      +                'newParentLocationId' => $this->parentLocationId,\n                   ]\n               );\n           }\n       \n      -\n           public function generateTags()\n           {\n               return [\n      -            'content-'.$this->contentId,\n      -            'relation-'.$this->contentId,\n      -            'location-'.$this->parentLocationId,\n      -            'parent-'.$this->parentLocationId,\n      +            'content-' . $this->contentId,\n      +            'relation-' . $this->contentId,\n      +            'location-' . $this->parentLocationId,\n      +            'parent-' . $this->parentLocationId,\n               ];\n           }\n       \n           public function getSlotClass()\n           {\n               return 'eZ\\Publish\\Core\\MVC\\Symfony\\Cache\\Http\\SignalSlot\\RecoverSlot';\n           }\n       \n           public function getReceivedSignalClasses()\n           {\n               return ['eZ\\Publish\\Core\\SignalSlot\\Signal\\TrashService\\RecoverSignal'];\n           }\n       }\n       \n      \n      ---------- end diff ----------\n\n   5) eZ/Publish/Core/MVC/Symfony/Cache/Tests/Http/SignalSlot/AbstractContentSlotTest.php (braces, concat_with_spaces)\n      ---------- begin diff ----------\n      --- Original\n      +++ New\n      @@ @@\n               $tags = [];\n      -        if ($this->contentId){\n      -            $tags = ['content-'.$this->contentId, 'relation-'.$this->contentId];\n      +        if ($this->contentId) {\n      +            $tags = ['content-' . $this->contentId, 'relation-' . $this->contentId];\n               }\n       \n               if ($this->locationId) {\n                   // self(s)\n      -            $tags[] = 'location-'.$this->locationId;\n      +            $tags[] = 'location-' . $this->locationId;\n                   // children\n      -            $tags[] = 'parent-'.$this->locationId;\n      +            $tags[] = 'parent-' . $this->locationId;\n               }\n       \n               if ($this->parentLocationId) {\n                   // parent(s)\n      -            $tags[] = 'location-'.$this->parentLocationId;\n      +            $tags[] = 'location-' . $this->parentLocationId;\n                   // siblings\n      -            $tags[] = 'parent-'.$this->parentLocationId;\n      +            $tags[] = 'parent-' . $this->parentLocationId;\n               }\n       \n               return $tags;\n           }\n       }\n       \n      \n      ---------- end diff ----------\n\n   6) eZ/Publish/Core/MVC/Symfony/Cache/Tests/Http/SignalSlot/UnhideLocationSlotTest.php (concat_with_spaces)\n      ---------- begin diff ----------\n      --- Original\n      +++ New\n      @@ @@\n               $tags = parent::generateTags();\n      -        $tags[] = 'path-'.$this->locationId;\n      +        $tags[] = 'path-' . $this->locationId;\n       \n               return $tags;\n           }\n       \n           public function getSlotClass()\n           {\n               return 'eZ\\Publish\\Core\\MVC\\Symfony\\Cache\\Http\\SignalSlot\\UnhideLocationSlot';\n           }\n       \n           public function getReceivedSignalClasses()\n           {\n               return ['eZ\\Publish\\Core\\SignalSlot\\Signal\\LocationService\\UnhideLocationSignal'];\n           }\n       }\n       \n      \n      ---------- end diff ----------\n\n   7) eZ/Publish/Core/MVC/Symfony/Cache/Tests/Http/SignalSlot/UpdateUserSlotTest.php (duplicate_semicolon, concat_with_spaces)\n      ---------- begin diff ----------\n      --- Original\n      +++ New\n      @@ @@\n           {\n      -        return ['content-'.$this->contentId];\n      -   ;\n      +        return ['content-' . $this->contentId];\n           }\n       \n           public function getSlotClass()\n           {\n               return 'eZ\\Publish\\Core\\MVC\\Symfony\\Cache\\Http\\SignalSlot\\UpdateUserSlot';\n           }\n       \n           public function getReceivedSignalClasses()\n           {\n               return ['eZ\\Publish\\Core\\SignalSlot\\Signal\\UserService\\UpdateUserSignal'];\n           }\n       }\n       \n      \n      ---------- end diff ----------\n\n   8) eZ/Publish/Core/MVC/Symfony/Cache/Tests/Http/SignalSlot/PublishVersionSlotTest.php (multiline_array_trailing_comma, extra_empty_lines)\n      ---------- begin diff ----------\n      --- Original\n      +++ New\n      @@ @@\n       \n      -\n      \n      @@ @@\n                       [\n      -                    new Location(['id' => $this->locationId, 'parentId' => $this->parentLocationId])\n      +                    new Location(['id' => $this->locationId, 'parentId' => $this->parentLocationId]),\n                       ]\n                   );\n      -\n       \n               $this->purgeClientMock->expects($this->once())->method('purgeByTags')->with($this->generateTags());\n               $this->purgeClientMock->expects($this->never())->method('purgeAll');\n               parent::receive($signal);\n           }\n       }\n       \n      \n      ---------- end diff ----------\n\n   9) eZ/Publish/Core/MVC/Symfony/Cache/Tests/Http/SignalSlot/DeleteLocationSlotTest.php (multiline_array_trailing_comma, concat_with_spaces)\n      ---------- begin diff ----------\n      --- Original\n      +++ New\n      @@ @@\n                       'locationId' => $this->locationId,\n      -                'parentLocationId' => $this->parentLocationId\n      +                'parentLocationId' => $this->parentLocationId,\n      \n      @@ @@\n               $tags = parent::generateTags();\n      -        $tags[] = 'path-'.$this->locationId;\n      +        $tags[] = 'path-' . $this->locationId;\n       \n               return $tags;\n           }\n       \n           public function getSlotClass()\n           {\n               return 'eZ\\Publish\\Core\\MVC\\Symfony\\Cache\\Http\\SignalSlot\\DeleteLocationSlot';\n           }\n       \n           public function getReceivedSignalClasses()\n           {\n               return ['eZ\\Publish\\Core\\SignalSlot\\Signal\\LocationService\\DeleteLocationSignal'];\n           }\n       }\n       \n      \n      ---------- end diff ----------\n\n  10) eZ/Publish/Core/MVC/Symfony/Cache/Tests/Http/SignalSlot/MoveSubtreeSlotTest.php (multiline_array_trailing_comma, concat_with_spaces)\n      ---------- begin diff ----------\n      --- Original\n      +++ New\n      @@ @@\n                       'locationId' => $this->locationId,\n      -                'newParentLocationId' => $this->parentLocationId\n      +                'newParentLocationId' => $this->parentLocationId,\n      \n      @@ @@\n           {\n      -        return ['path-'.$this->locationId, 'location-'.$this->parentLocationId, 'parent-'.$this->parentLocationId];\n      +        return ['path-' . $this->locationId, 'location-' . $this->parentLocationId, 'parent-' . $this->parentLocationId];\n           }\n       \n           public function getSlotClass()\n           {\n               return 'eZ\\Publish\\Core\\MVC\\Symfony\\Cache\\Http\\SignalSlot\\MoveSubtreeSlot';\n           }\n       \n           public function getReceivedSignalClasses()\n           {\n               return ['eZ\\Publish\\Core\\SignalSlot\\Signal\\LocationService\\MoveSubtreeSignal'];\n           }\n       }\n       \n      \n      ---------- end diff ----------\n\n  11) eZ/Publish/Core/MVC/Symfony/Cache/Tests/Http/SignalSlot/AssignUserToUserGroupSlotTest.php (eof_ending, concat_with_spaces)\n      ---------- begin diff ----------\n      --- Original\n      +++ New\n      @@ @@\n           {\n      -        return ['content-'.$this->contentId, 'content-99'];\n      +        return ['content-' . $this->contentId, 'content-99'];\n      \n      @@ @@\n       }\n      +\n      \n      ---------- end diff ----------\n\n  12) eZ/Publish/Core/MVC/Symfony/Cache/Tests/Http/SignalSlot/CopyContentSlotTest.php (concat_with_spaces)\n      ---------- begin diff ----------\n      --- Original\n      +++ New\n      @@ @@\n           {\n      -        return ['content-'.$this->contentId, 'location-'.$this->parentLocationId, 'path-'.$this->parentLocationId];\n      +        return ['content-' . $this->contentId, 'location-' . $this->parentLocationId, 'path-' . $this->parentLocationId];\n           }\n       \n           public function getSlotClass()\n           {\n               return 'eZ\\Publish\\Core\\MVC\\Symfony\\Cache\\Http\\SignalSlot\\CopyContentSlot';\n           }\n       \n           public function getReceivedSignalClasses()\n           {\n               return ['eZ\\Publish\\Core\\SignalSlot\\Signal\\ContentService\\CopyContentSignal'];\n           }\n       }\n       \n      \n      ---------- end diff ----------\n\n  13) eZ/Publish/Core/MVC/Symfony/Cache/Tests/Http/SignalSlot/TrashSlotTest.php (multiline_array_trailing_comma)\n      ---------- begin diff ----------\n      --- Original\n      +++ New\n      @@ @@\n                       'locationId' => $this->locationId,\n      -                'parentLocationId' => $this->parentLocationId\n      +                'parentLocationId' => $this->parentLocationId,\n                   ]\n               );\n           }\n       \n           public function getSlotClass()\n           {\n               return 'eZ\\Publish\\Core\\MVC\\Symfony\\Cache\\Http\\SignalSlot\\TrashSlot';\n           }\n       \n           public function getReceivedSignalClasses()\n           {\n               return ['eZ\\Publish\\Core\\SignalSlot\\Signal\\TrashService\\TrashSignal'];\n           }\n       }\n       \n      \n      ---------- end diff ----------\n\n  14) eZ/Publish/Core/MVC/Symfony/Cache/Tests/Http/SignalSlot/HideLocationSlotTest.php (concat_with_spaces)\n      ---------- begin diff ----------\n      --- Original\n      +++ New\n      @@ @@\n               $tags = parent::generateTags();\n      -        $tags[] = 'path-'.$this->locationId;\n      +        $tags[] = 'path-' . $this->locationId;\n       \n               return $tags;\n           }\n       \n           public function getSlotClass()\n           {\n               return 'eZ\\Publish\\Core\\MVC\\Symfony\\Cache\\Http\\SignalSlot\\HideLocationSlot';\n           }\n       \n           public function getReceivedSignalClasses()\n           {\n               return ['eZ\\Publish\\Core\\SignalSlot\\Signal\\LocationService\\HideLocationSignal'];\n           }\n       }\n       \n      \n      ---------- end diff ----------\n\n  15) eZ/Publish/Core/MVC/Symfony/Cache/Tests/Http/SignalSlot/DeleteContentSlotTest.php (extra_empty_lines)\n      ---------- begin diff ----------\n      --- Original\n      +++ New\n      @@ @@\n       \n      -\n           public function generateTags()\n           {\n               $tags = parent::generateTags();\n               $tags[] = 'path-45';\n               $tags[] = 'path-55';\n       \n               return $tags;\n           }\n       \n           public function getSlotClass()\n           {\n               return 'eZ\\Publish\\Core\\MVC\\Symfony\\Cache\\Http\\SignalSlot\\DeleteContentSlot';\n           }\n       \n           public function getReceivedSignalClasses()\n           {\n               return ['eZ\\Publish\\Core\\SignalSlot\\Signal\\ContentService\\DeleteContentSignal'];\n           }\n       }\n       \n      \n      ---------- end diff ----------\n\n  16) eZ/Publish/Core/MVC/Symfony/Cache/Http/ContentPurger.php (phpdoc_no_package, phpdoc_trim)\n      ---------- begin diff ----------\n      --- Original\n      +++ New\n      @@ @@\n        * indicating which objects to purge.\n      - *\n      - * @package  eZ\\Publish\\Core\\MVC\\Symfony\\Cache\\Http\\ProxyCacheStore\n        */\n       interface ContentPurger extends RequestAwarePurger\n       {\n           /**\n            * Purges all cached content.\n            *\n            * @return bool\n            */\n           public function purgeAllContent();\n       }\n       \n      \n      ---------- end diff ----------\n\n  17) eZ/Publish/Core/MVC/Symfony/Cache/Http/SignalSlot/PublishContentTypeSlot.php (concat_with_spaces)\n      ---------- begin diff ----------\n      --- Original\n      +++ New\n      @@ @@\n           {\n      -        return $this->purgeClient->purgeByTags(['content-type-'.$signal->contentTypeDraftId]);\n      +        return $this->purgeClient->purgeByTags(['content-type-' . $signal->contentTypeDraftId]);\n           }\n       }\n       \n      \n      ---------- end diff ----------\n\n  18) eZ/Publish/Core/MVC/Symfony/Cache/Http/SignalSlot/UpdateUserSlot.php (concat_with_spaces)\n      ---------- begin diff ----------\n      --- Original\n      +++ New\n      @@ @@\n           {\n      -        return ['content-'.$signal->userId];\n      +        return ['content-' . $signal->userId];\n           }\n       \n           protected function supports(Signal $signal)\n           {\n               return $signal instanceof Signal\\UserService\\UpdateUserSignal;\n           }\n       }\n       \n      \n      ---------- end diff ----------\n\n  19) eZ/Publish/Core/MVC/Symfony/Cache/Http/SignalSlot/DeleteContentTypeSlot.php (concat_with_spaces)\n      ---------- begin diff ----------\n      --- Original\n      +++ New\n      @@ @@\n           {\n      -        return $this->purgeClient->purgeByTags(['content-type-'.$signal->contentTypeId]);\n      +        return $this->purgeClient->purgeByTags(['content-type-' . $signal->contentTypeId]);\n           }\n       }\n       \n      \n      ---------- end diff ----------\n\n  20) eZ/Publish/Core/MVC/Symfony/Cache/Http/SignalSlot/CopyContentSlot.php (concat_with_spaces)\n      ---------- begin diff ----------\n      --- Original\n      +++ New\n      @@ @@\n           {\n      -        return ['content-'.$signal->dstContentId, 'location-'.$signal->dstParentLocationId, 'path-'.$signal->dstParentLocationId];\n      +        return ['content-' . $signal->dstContentId, 'location-' . $signal->dstParentLocationId, 'path-' . $signal->dstParentLocationId];\n           }\n       \n           protected function supports(Signal $signal)\n           {\n               return $signal instanceof Signal\\ContentService\\CopyContentSignal;\n           }\n       }\n       \n      \n      ---------- end diff ----------\n\n  21) eZ/Publish/Core/MVC/Symfony/Cache/Http/SignalSlot/RecoverSlot.php (concat_with_spaces)\n      ---------- begin diff ----------\n      --- Original\n      +++ New\n      @@ @@\n               $tags = parent::generateTags($signal);\n      -        $tags[] = 'location-'.$signal->newParentLocationId;\n      -        $tags[] = 'parent-'.$signal->newParentLocationId;\n      +        $tags[] = 'location-' . $signal->newParentLocationId;\n      +        $tags[] = 'parent-' . $signal->newParentLocationId;\n       \n               return $tags;\n           }\n       \n           protected function supports(Signal $signal)\n           {\n               return $signal instanceof Signal\\TrashService\\RecoverSignal;\n           }\n       }\n       \n      \n      ---------- end diff ----------\n\n  22) eZ/Publish/Core/MVC/Symfony/Cache/Http/SignalSlot/MoveSubtreeSlot.php (multiline_array_trailing_comma, concat_with_spaces)\n      ---------- begin diff ----------\n      --- Original\n      +++ New\n      @@ @@\n               return [\n      -            'path-'.$signal->locationId,\n      -            'location-'.$signal->newParentLocationId,\n      -            'parent-'.$signal->newParentLocationId\n      +            'path-' . $signal->locationId,\n      +            'location-' . $signal->newParentLocationId,\n      +            'parent-' . $signal->newParentLocationId,\n               ];\n           }\n       \n           protected function supports(Signal $signal)\n           {\n               return $signal instanceof Signal\\LocationService\\MoveSubtreeSignal;\n           }\n       }\n       \n      \n      ---------- end diff ----------\n\n  23) eZ/Publish/Core/MVC/Symfony/Cache/Http/SignalSlot/UnassignUserFromUserGroupSlot.php (concat_with_spaces)\n      ---------- begin diff ----------\n      --- Original\n      +++ New\n      @@ @@\n           {\n      -        return ['content-'.$signal->userId, 'content-'.$signal->userGroupId];\n      +        return ['content-' . $signal->userId, 'content-' . $signal->userGroupId];\n           }\n       \n           protected function supports(Signal $signal)\n           {\n               return $signal instanceof Signal\\UserService\\UnAssignUserFromUserGroupSignal;\n           }\n       }\n       \n      \n      ---------- end diff ----------\n\n  24) eZ/Publish/Core/MVC/Symfony/Cache/Http/SignalSlot/UnhideLocationSlot.php (concat_with_spaces)\n      ---------- begin diff ----------\n      --- Original\n      +++ New\n      @@ @@\n               $tags = parent::generateTags($signal);\n      -        $tags[] = 'path-'.$signal->locationId;\n      +        $tags[] = 'path-' . $signal->locationId;\n       \n               return $tags;\n           }\n       \n           protected function supports(Signal $signal)\n           {\n               return $signal instanceof Signal\\LocationService\\UnhideLocationSignal;\n           }\n       }\n       \n      \n      ---------- end diff ----------\n\n  25) eZ/Publish/Core/MVC/Symfony/Cache/Http/SignalSlot/AssignUserToUserGroupSlot.php (concat_with_spaces)\n      ---------- begin diff ----------\n      --- Original\n      +++ New\n      @@ @@\n           {\n      -        return ['content-'.$signal->userId, 'content-'.$signal->userGroupId];\n      +        return ['content-' . $signal->userId, 'content-' . $signal->userGroupId];\n           }\n       \n           protected function supports(Signal $signal)\n           {\n               return $signal instanceof Signal\\UserService\\AssignUserToUserGroupSignal;\n           }\n       }\n       \n      \n      ---------- end diff ----------\n\n  26) eZ/Publish/Core/MVC/Symfony/Cache/Http/SignalSlot/DeleteContentSlot.php (concat_with_spaces)\n      ---------- begin diff ----------\n      --- Original\n      +++ New\n      @@ @@\n               foreach ($signal->affectedLocationIds as $locationId) {\n      -            $tags[] = 'path-'.$locationId;\n      +            $tags[] = 'path-' . $locationId;\n               }\n       \n               return $tags;\n           }\n       \n           protected function supports(Signal $signal)\n           {\n               return $signal instanceof Signal\\ContentService\\DeleteContentSignal;\n           }\n       }\n       \n      \n      ---------- end diff ----------\n\n  27) eZ/Publish/Core/MVC/Symfony/Cache/Http/SignalSlot/AbstractContentSlot.php (concat_with_spaces)\n      ---------- begin diff ----------\n      --- Original\n      +++ New\n      @@ @@\n                   // self in all forms (also withouth locations)\n      -            $tags[] = 'content-'.$signal->contentId;\n      +            $tags[] = 'content-' . $signal->contentId;\n                   // reverse relations\n      -            $tags[] = 'relation-'.$signal->contentId;\n      +            $tags[] = 'relation-' . $signal->contentId;\n               }\n       \n               if (isset($signal->locationId)) {\n                   // self\n      -            $tags[] = 'location-'.$signal->locationId;\n      +            $tags[] = 'location-' . $signal->locationId;\n                   // direct children\n      -            $tags[] = 'parent-'.$signal->locationId;\n      +            $tags[] = 'parent-' . $signal->locationId;\n               }\n       \n               if (isset($signal->parentLocationId)) {\n                   // direct parent\n      -            $tags[] = 'location-'.$signal->parentLocationId;\n      +            $tags[] = 'location-' . $signal->parentLocationId;\n                   // direct siblings\n      -            $tags[] = 'parent-'.$signal->parentLocationId;\n      +            $tags[] = 'parent-' . $signal->parentLocationId;\n               }\n       \n               return $tags;\n           }\n       }\n       \n      \n      ---------- end diff ----------\n\n  28) eZ/Publish/Core/MVC/Symfony/Cache/Http/SignalSlot/HideLocationSlot.php (concat_with_spaces)\n      ---------- begin diff ----------\n      --- Original\n      +++ New\n      @@ @@\n               $tags = parent::generateTags($signal);\n      -        $tags[] = 'path-'.$signal->locationId;\n      +        $tags[] = 'path-' . $signal->locationId;\n       \n               return $tags;\n           }\n       \n           protected function supports(Signal $signal)\n           {\n               return $signal instanceof Signal\\LocationService\\HideLocationSignal;\n           }\n       }\n       \n      \n      ---------- end diff ----------\n\n  29) eZ/Publish/Core/MVC/Symfony/Cache/Http/SignalSlot/PublishVersionSlot.php (single_line_after_imports, concat_with_spaces)\n      ---------- begin diff ----------\n      --- Original\n      +++ New\n      @@ @@\n       \n      -\n      \n      @@ @@\n                   // self\n      -            $tags[] = 'location-'.$location->id;\n      +            $tags[] = 'location-' . $location->id;\n                   // children\n      -            $tags[] = 'parent-'.$location->id;\n      +            $tags[] = 'parent-' . $location->id;\n                   // parent\n      -            $tags[] = 'location-'.$location->parentId;\n      +            $tags[] = 'location-' . $location->parentId;\n                   // siblings\n      -            $tags[] = 'parent-'.$location->parentId;\n      +            $tags[] = 'parent-' . $location->parentId;\n               }\n       \n               return $tags;\n           }\n       \n           protected function supports(Signal $signal)\n           {\n               return $signal instanceof Signal\\ContentService\\PublishVersionSignal;\n           }\n       }\n       \n      \n      ---------- end diff ----------\n\n  30) eZ/Publish/Core/MVC/Symfony/Cache/Http/SignalSlot/DeleteLocationSlot.php (unused_use, concat_with_spaces)\n      ---------- begin diff ----------\n      --- Original\n      +++ New\n      @@ @@\n       \n      -use eZ\\Publish\\API\\Repository\\Exceptions\\NotFoundException;\n      \n      @@ @@\n               $tags = parent::generateTags($signal);\n      -        $tags[] = 'path-'.$signal->locationId;\n      +        $tags[] = 'path-' . $signal->locationId;\n       \n               return $tags;\n           }\n       \n           protected function supports(Signal $signal)\n           {\n               return $signal instanceof Signal\\LocationService\\DeleteLocationSignal;\n           }\n       }\n       \n      \n      ---------- end diff ----------\n\n  31) eZ/Publish/Core/MVC/Symfony/Cache/Http/SignalSlot/SwapLocationSlot.php (concat_with_spaces)\n      ---------- begin diff ----------\n      --- Original\n      +++ New\n      @@ @@\n               return [\n      -            'location-'.$signal->location1Id,\n      -            'parent-'.$signal->location1Id,\n      -            'location-'.$signal->location1Id,\n      -            'parent-'.$signal->location2Id,\n      +            'location-' . $signal->location1Id,\n      +            'parent-' . $signal->location1Id,\n      +            'location-' . $signal->location1Id,\n      +            'parent-' . $signal->location2Id,\n               ];\n           }\n       \n           protected function supports(Signal $signal)\n           {\n               return $signal instanceof Signal\\LocationService\\SwapLocationSignal;\n           }\n       }\n       \n      \n      ---------- end diff ----------\n\n  32) eZ/Publish/Core/MVC/Symfony/Cache/Http/Proxy/TagAwareStore.php (new_with_braces, elseif, function_declaration, concat_with_spaces)\n      ---------- begin diff ----------\n      --- Original\n      +++ New\n      @@ @@\n           {\n      -        $path = $this->getTagPath($tag).DIRECTORY_SEPARATOR.$digest;\n      +        $path = $this->getTagPath($tag) . DIRECTORY_SEPARATOR . $digest;\n      \n      @@ @@\n                   $tags = explode(' ', $request->headers->get('xkey'));\n      -        } else if ($locationId[0] === '(' && substr($locationId, -1) === ')') {\n      +        } elseif ($locationId[0] === '(' && substr($locationId, -1) === ')') {\n                   // Deprecated: (123|456|789) => Purge for #123, #456 and #789 location IDs.\n                   $tags = array_map(\n      -                function($id){return 'location-' . $id;},\n      +                function ($id) {return 'location-' . $id;},\n      \n      @@ @@\n       \n      -        $files = (new Finder)->files()->in($cacheTagsCacheDir);\n      +        $files = (new Finder())->files()->in($cacheTagsCacheDir);\n      \n      @@ @@\n           {\n      -        $path = $this->root.DIRECTORY_SEPARATOR.static::TAG_CACHE_DIR;\n      +        $path = $this->root . DIRECTORY_SEPARATOR . static::TAG_CACHE_DIR;\n               if ($tag) {\n                   // Flip the tag so we put id first so it gets sliced into folders.\n                   // (otherwise we would easily reach inode limits on file system)\n                   $tag = strrev($tag);\n      -            $path .= DIRECTORY_SEPARATOR.substr($tag, 0, 2).DIRECTORY_SEPARATOR.substr($tag, 2, 2).DIRECTORY_SEPARATOR.substr($tag, 4);\n      +            $path .= DIRECTORY_SEPARATOR . substr($tag, 0, 2) . DIRECTORY_SEPARATOR . substr($tag, 2, 2) . DIRECTORY_SEPARATOR . substr($tag, 4);\n               }\n       \n               return $path;\n           }\n       }\n       \n      \n      ---------- end diff ----------\n\n  33) eZ/Publish/Core/MVC/Symfony/Cache/Http/InstantCachePurger.php (phpdoc_no_package, phpdoc_short_description)\n      ---------- begin diff ----------\n      --- Original\n      +++ New\n      @@ @@\n       /**\n      - * Class InstantCachePurger\n      + * Class InstantCachePurger.\n        *\n      - * @package eZ\\Publish\\Core\\MVC\\Symfony\\Cache\\Http\n        * @deprecated since 6.6 will be removed in 7.0, use PurgeClient directly.\n        */\n       class InstantCachePurger implements GatewayCachePurger\n       {\n           /**\n            * @var PurgeClientInterface\n            */\n           protected $purgeClient;\n       \n           /**\n            * @var ContentService\n            */\n           private $contentService;\n       \n           /**\n            * @var EventDispatcherInterface\n            */\n           private $eventDispatcher;\n       \n           public function __construct(\n               PurgeClientInterface $purgeClient,\n               ContentService $contentService,\n               EventDispatcherInterface $eventDispatcher\n           ) {\n               $this->purgeClient = $purgeClient;\n               $this->contentService = $contentService;\n               $this->eventDispatcher = $eventDispatcher;\n           }\n       \n           /**\n            * {@inheritdoc}\n            */\n           public function purge($locationIds)\n           {\n               $this->purgeClient->purge((array)$locationIds);\n       \n               return $locationIds;\n           }\n       \n           /**\n            * {@inheritdoc}\n            */\n           public function purgeAll()\n           {\n               $this->purgeClient->purgeAll();\n           }\n       \n           /**\n            * {@inheritdoc}\n            */\n           public function purgeForContent($contentId, $locationIds = [])\n           {\n               $contentInfo = $this->contentService->loadContentInfo($contentId);\n       \n               // Can only gather relevant locations using ContentCacheClearEvent on published content\n               if ($contentInfo->published) {\n                   $event = new ContentCacheClearEvent($contentInfo);\n                   $this->eventDispatcher->dispatch(MVCEvents::CACHE_CLEAR_CONTENT, $event);\n       \n                   foreach ($event->getLocationsToClear() as $location) {\n                       $locationIds[] = $location->id;\n                   }\n               }\n       \n               $this->purgeClient->purge(array_unique($locationIds));\n           }\n       }\n       \n      \n      ---------- end diff ----------\n\n  34) eZ/Publish/Core/MVC/Symfony/Cache/Http/LocalPurgeClient.php (phpdoc_inline_tag)\n      ---------- begin diff ----------\n      --- Original\n      +++ New\n      @@ @@\n           /**\n      -     * @inheritdoc\n      +     * {@inheritdoc}\n      \n      @@ @@\n           /**\n      -     * @inheritdoc\n      +     * {@inheritdoc}\n      \n      @@ @@\n           /**\n      -     * @inheritdoc\n      +     * {@inheritdoc}\n            */\n           public function purgeAll()\n           {\n               $this->cacheStore->purgeAllContent();\n           }\n       }\n       \n      \n      ---------- end diff ----------\n\n  35) eZ/Publish/Core/MVC/Symfony/Cache/Http/RequestAwarePurger.php (phpdoc_no_package, phpdoc_trim)\n      ---------- begin diff ----------\n      --- Original\n      +++ New\n      @@ @@\n        * Interface allowing implementor (cache Store) to purge Http cache from a request object.\n      - *\n      - * @package  eZ\\Publish\\Core\\MVC\\Symfony\\Cache\\Http\\ProxyCacheStore\n        */\n       interface RequestAwarePurger\n       {\n           /**\n            * Purges data from $request.\n            *\n            * @param \\Symfony\\Component\\HttpFoundation\\Request $request\n            *\n            * @return bool True if purge was successful. False otherwise\n            */\n           public function purgeByRequest(Request $request);\n       }\n       \n      \n      ---------- end diff ----------\n\n  36) eZ/Publish/Core/REST/Server/Output/ValueObjectVisitor/CachedValue.php (concat_with_spaces)\n      ---------- begin diff ----------\n      --- Original\n      +++ New\n      @@ @@\n                       foreach ((array)$values as $value) {\n      -                    $tags[] = $tag . '-'. $value;\n      +                    $tags[] = $tag . '-' . $value;\n                       }\n                   }\n       \n                   $response->headers->set(\n                       'xkey',\n                       $tags,\n                       false\n                   );\n               }\n           }\n       \n           public function getParameter($parameterName, $defaultValue = null)\n           {\n               if ($this->configResolver->hasParameter($parameterName)) {\n                   return $this->configResolver->getParameter($parameterName);\n               }\n       \n               return $defaultValue;\n           }\n       }\n       \n      \n      ---------- end diff ----------\n\nFixed all files in 431.234 seconds, 27.500 MB memory used\n```\n"}}
{"actor":{"display_login":"ezrobot"}}