Skip to content

Commit 5517ade

Browse files
committed
Fix #167 (ManyToMany cache purge), #113 edge cases, and PageDataProvider 500 on unknown path
- PropagateUpdatesListener: walk getScheduledCollectionUpdates/Deletions to purge owning entities (Page/Layout) when ComponentGroup ManyToMany joins change - PageDataProvider.getPageData: catch exceptions from getResourceFromIri so invalid paths (e.g. /unknown-path) return null instead of 500 - Behat: two new component_groups.feature scenarios verify Page/Layout cache purge after PATCH links an existing ComponentGroup - Behat: two new dynamic_page.feature scenarios confirm admin fetch without path header and fetch with unknown path both return 200 with component=null - Behat: security.feature scenario confirms /me resolves by username after user entity is recreated with a new database ID (no code change needed)
1 parent 074de14 commit 5517ade

6 files changed

Lines changed: 80 additions & 1 deletion

File tree

features/bootstrap/DoctrineContext.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,24 @@ public function deleteLoggedInUser(): void
201201
$this->manager->clear();
202202
}
203203

204+
/**
205+
* @Given the logged in user has been recreated with the same username
206+
*/
207+
public function theLoggedInUserHasBeenRecreatedWithSameUsername(): void
208+
{
209+
$user = new User();
210+
$user
211+
->setRoles(['ROLE_ADMIN'])
212+
->setUsername('new_user')
213+
->setEmailAddress('recreated@example.com')
214+
->setPassword($this->passwordHasher->hashPassword($user, 'password'))
215+
->setEnabled(true)
216+
->setEmailAddressVerified(true);
217+
$this->timestampedHelper->persistTimestampedFields($user, true);
218+
$this->manager->persist($user);
219+
$this->manager->flush();
220+
}
221+
204222
/**
205223
* @Given there is a :type form
206224
*/

features/main/component_groups.feature

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,3 +105,23 @@ Feature: ComponentGroup resource
105105
Then the response status code should be 200
106106
And the JSON node "componentPositions" should have 1 element
107107
And the JSON node "componentPositions[0]" should be equal to the IRI of the resource "position_0"
108+
109+
@loginAdmin
110+
Scenario: Linking an existing ComponentGroup to a Page via PATCH purges the Page from the cache
111+
Given there is a Page
112+
And there is a ComponentGroup with 0 components
113+
When I send a "PATCH" request to the resource "component_group" with data:
114+
| pages |
115+
| json_decode([ "resource[page]" ]) |
116+
Then the response status code should be 200
117+
And the resource "page" should be purged from the cache
118+
119+
@loginAdmin
120+
Scenario: Linking an existing ComponentGroup to a Layout via PATCH purges the Layout from the cache
121+
Given there is a Layout
122+
And there is a ComponentGroup with 0 components
123+
When I send a "PATCH" request to the resource "component_group" with data:
124+
| layouts |
125+
| json_decode([ "resource[layout]" ]) |
126+
Then the response status code should be 200
127+
And the resource "layout" should be purged from the cache

features/main/dynamic_page.feature

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,3 +65,20 @@ Feature: Dynamic pages
6565
Then the response status code should be 200
6666
And the resource "component_position" should exist
6767
And the resource "component_position" should be purged from the cache
68+
69+
@loginAdmin
70+
Scenario: An admin can fetch a pageDataProperty position without a path header and the component slot is not resolved
71+
Given there is a PageData resource with the route path "/page-data"
72+
When I send a "GET" request to the resource "component_position"
73+
Then the response status code should be 200
74+
And the JSON node "pageDataProperty" should be equal to "component"
75+
And the JSON node "component" should be null
76+
77+
@loginAdmin
78+
Scenario: Fetching a pageDataProperty position with a path that has no matching page data returns the position without a component
79+
Given there is a PageData resource with the route path "/page-data"
80+
And I add "path" header equal to "/unknown-path"
81+
When I send a "GET" request to the resource "component_position"
82+
Then the response status code should be 200
83+
And the JSON node "pageDataProperty" should be equal to "component"
84+
And the JSON node "component" should be null

features/main/security.feature

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,3 +185,11 @@ Feature: Restrict loading of components and routes
185185
When I send a "GET" request to "/me"
186186
Then the response status code should be 401
187187
And the response should have a "api_components" cookie with max age less than 2
188+
189+
@loginAdmin
190+
Scenario: GET /me resolves the user by username even after the user entity is recreated with a new database ID
191+
Given the logged in user has been deleted from the database
192+
And the logged in user has been recreated with the same username
193+
When I send a "GET" request to "/me"
194+
Then the response status code should be 200
195+
And the JSON node "username" should be equal to "new_user"

src/DataProvider/PageDataProvider.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,11 @@ public function getPageData(): ?AbstractPageData
6565

6666
$route = $this->routeRepository->findOneByIdOrPath($path);
6767
if (!$route) {
68-
$object = $this->iriConverter->getResourceFromIri($path);
68+
try {
69+
$object = $this->iriConverter->getResourceFromIri($path);
70+
} catch (\Exception) {
71+
return null;
72+
}
6973
if ($object instanceof AbstractPageData) {
7074
return $object;
7175
}

src/EventListener/Doctrine/PropagateUpdatesListener.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,18 @@ public function onFlush(OnFlushEventArgs $eventArgs): void
7575
$this->gatherResourceAndAssociated($entity, 'deleted', $em, $uow);
7676
}
7777

78+
// ManyToMany join table changes — purge the owning entity's cache
79+
foreach ($uow->getScheduledCollectionUpdates() as $collection) {
80+
if ($owner = $collection->getOwner()) {
81+
$this->collectUpdatedResource($owner, 'updated');
82+
}
83+
}
84+
foreach ($uow->getScheduledCollectionDeletions() as $collection) {
85+
if ($owner = $collection->getOwner()) {
86+
$this->collectUpdatedResource($owner, 'updated');
87+
}
88+
}
89+
7890
$this->collectUpdatedPageDataAndPositions();
7991
}
8092

0 commit comments

Comments
 (0)