Skip to content

Commit b370c42

Browse files
authored
Support wildcard tag clearing, and track collections (#30)
2 parents e92675d + bcc8474 commit b370c42

File tree

4 files changed

+119
-7
lines changed

4 files changed

+119
-7
lines changed

src/Http/Middleware/CacheTracker.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,20 +129,23 @@ private function setupAugmentationHooks(string $url)
129129

130130
app(Entry::class)::hook('augmented', function ($augmented, $next) use ($self) {
131131
$self->addContentTag($this->collection()->handle().':'.$this->id());
132+
$self->addContentTag('collection:'.$this->collection()->handle());
132133

133134
return $next($augmented);
134135
});
135136

136137
Page::hook('augmented', function ($augmented, $next) use ($self) {
137138
if ($entry = $this->entry()) {
138139
$self->addContentTag($entry->collection()->handle().':'.$entry->id());
140+
$self->addContentTag('collection:'.$entry->collection()->handle());
139141
}
140142

141143
return $next($augmented);
142144
});
143145

144146
LocalizedTerm::hook('augmented', function ($augmented, $next) use ($self) {
145147
$self->addContentTag('term:'.$this->id());
148+
$self->addContentTag('taxonomy:'.$this->taxonomy()->handle());
146149

147150
return $next($augmented);
148151
});

src/Tracker/Manager.php

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ public function invalidate(array $tags = [])
8181
$storeTags = $data['tags'];
8282
$url = $data['url'];
8383

84-
if (count(array_intersect($tags, $storeTags)) > 0) {
84+
if ($this->tagsMatch($tags, $storeTags)) {
8585
$urls[] = $url;
8686

8787
unset($storeData[$key]);
@@ -97,6 +97,25 @@ public function invalidate(array $tags = [])
9797
return $this;
9898
}
9999

100+
private function tagsMatch(array $tagsToInvalidate, array $storeTags): bool
101+
{
102+
foreach ($tagsToInvalidate as $tag) {
103+
// Handle wildcard tags (ending with *)
104+
if (str_ends_with($tag, '*')) {
105+
$prefix = substr($tag, 0, -1);
106+
foreach ($storeTags as $storeTag) {
107+
if (str_starts_with($storeTag, $prefix)) {
108+
return true;
109+
}
110+
}
111+
} elseif (in_array($tag, $storeTags)) {
112+
return true;
113+
}
114+
}
115+
116+
return false;
117+
}
118+
100119
private function invalidateUrls($urls)
101120
{
102121
$cacher = app(Cacher::class);

tests/Unit/AdditionalTrackerTest.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ public function tracks_additional_closures()
1717

1818
$this->get('/');
1919

20-
$this->assertSame(['test::tag', 'pages:home'], collect(Tracker::all())->firstWhere('url', 'http://localhost')['tags']);
20+
$this->assertSame(['test::tag', 'pages:home', 'collection:pages'], collect(Tracker::all())->firstWhere('url', 'http://localhost')['tags']);
2121
}
2222

2323
#[Test]
@@ -27,7 +27,7 @@ public function tracks_additional_classes()
2727

2828
$this->get('/');
2929

30-
$this->assertSame(['additional::tag', 'pages:home'], collect(Tracker::all())->firstWhere('url', 'http://localhost')['tags']);
30+
$this->assertSame(['additional::tag', 'pages:home', 'collection:pages'], collect(Tracker::all())->firstWhere('url', 'http://localhost')['tags']);
3131
}
3232
}
3333

tests/Unit/TrackerTest.php

Lines changed: 94 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ public function it_tracks_uncached_pages()
2222

2323
$this->get('/');
2424

25-
$this->assertSame(['test::tag', 'pages:home'], collect(Tracker::all())->first()['tags']);
25+
$this->assertSame(['test::tag', 'pages:home', 'collection:pages'], collect(Tracker::all())->first()['tags']);
2626

2727
Event::assertDispatched(ContentTracked::class, 1);
2828
}
@@ -38,11 +38,11 @@ public function it_doesnt_track_already_cached_pages()
3838

3939
$this->get('/');
4040

41-
$this->assertSame(['test::tag', 'pages:home'], collect(Tracker::all())->first()['tags']);
41+
$this->assertSame(['test::tag', 'pages:home', 'collection:pages'], collect(Tracker::all())->first()['tags']);
4242

4343
$this->get('/');
4444

45-
$this->assertSame(['test::tag', 'pages:home'], collect(Tracker::all())->first()['tags']);
45+
$this->assertSame(['test::tag', 'pages:home', 'collection:pages'], collect(Tracker::all())->first()['tags']);
4646

4747
Event::assertDispatched(ContentTracked::class, 1);
4848
}
@@ -82,7 +82,7 @@ public function it_flushes()
8282

8383
$this->get('/');
8484

85-
$this->assertSame(['test::tag', 'pages:home'], collect(Tracker::all())->first()['tags']);
85+
$this->assertSame(['test::tag', 'pages:home', 'collection:pages'], collect(Tracker::all())->first()['tags']);
8686

8787
$this->assertCount(1, Tracker::all());
8888

@@ -91,4 +91,94 @@ public function it_flushes()
9191
$this->assertCount(0, Tracker::all());
9292
Event::assertDispatched(UrlInvalidated::class);
9393
}
94+
95+
#[Test]
96+
public function it_invalidates_by_exact_tag_match()
97+
{
98+
Tracker::add('/page1', ['products:1', 'category:electronics']);
99+
Tracker::add('/page2', ['products:2', 'category:books']);
100+
Tracker::add('/page3', ['products:3', 'category:electronics']);
101+
102+
$this->assertCount(3, Tracker::all());
103+
104+
Tracker::invalidate(['products:1']);
105+
106+
$this->assertCount(2, Tracker::all());
107+
$this->assertNull(Tracker::get('/page1'));
108+
$this->assertNotNull(Tracker::get('/page2'));
109+
$this->assertNotNull(Tracker::get('/page3'));
110+
}
111+
112+
#[Test]
113+
public function it_invalidates_by_wildcard_tag()
114+
{
115+
Tracker::add('/page1', ['products:1', 'category:electronics']);
116+
Tracker::add('/page2', ['products:2', 'category:books']);
117+
Tracker::add('/page3', ['products:3', 'category:electronics']);
118+
119+
$this->assertCount(3, Tracker::all());
120+
121+
Tracker::invalidate(['products:*']);
122+
123+
$this->assertCount(0, Tracker::all());
124+
}
125+
126+
#[Test]
127+
public function it_invalidates_by_wildcard_tag_with_prefix()
128+
{
129+
Tracker::add('/page1', ['products:1', 'category:electronics']);
130+
Tracker::add('/page2', ['products:2', 'category:books']);
131+
Tracker::add('/page3', ['articles:1', 'category:electronics']);
132+
133+
$this->assertCount(3, Tracker::all());
134+
135+
Tracker::invalidate(['products:*']);
136+
137+
$this->assertCount(1, Tracker::all());
138+
$this->assertNull(Tracker::get('/page1'));
139+
$this->assertNull(Tracker::get('/page2'));
140+
$this->assertNotNull(Tracker::get('/page3'));
141+
}
142+
143+
#[Test]
144+
public function it_invalidates_by_multiple_wildcard_tags()
145+
{
146+
Tracker::add('/page1', ['products:1', 'category:electronics']);
147+
Tracker::add('/page2', ['products:2', 'category:books']);
148+
Tracker::add('/page3', ['articles:1', 'author:john']);
149+
Tracker::add('/page4', ['videos:1', 'author:jane']);
150+
151+
$this->assertCount(4, Tracker::all());
152+
153+
Tracker::invalidate(['products:*', 'author:*']);
154+
155+
$this->assertCount(0, Tracker::all());
156+
}
157+
158+
#[Test]
159+
public function it_invalidates_by_mixed_exact_and_wildcard_tags()
160+
{
161+
Tracker::add('/page1', ['products:1', 'category:electronics']);
162+
Tracker::add('/page2', ['products:2', 'category:books']);
163+
Tracker::add('/page3', ['articles:1', 'featured']);
164+
165+
$this->assertCount(3, Tracker::all());
166+
167+
Tracker::invalidate(['products:*', 'featured']);
168+
169+
$this->assertCount(0, Tracker::all());
170+
}
171+
172+
#[Test]
173+
public function it_doesnt_invalidate_when_wildcard_doesnt_match()
174+
{
175+
Tracker::add('/page1', ['products:1', 'category:electronics']);
176+
Tracker::add('/page2', ['articles:1', 'category:books']);
177+
178+
$this->assertCount(2, Tracker::all());
179+
180+
Tracker::invalidate(['videos:*']);
181+
182+
$this->assertCount(2, Tracker::all());
183+
}
94184
}

0 commit comments

Comments
 (0)