Skip to content

Commit e4eb1c3

Browse files
committed
Merge branch '5.x'
# Conflicts: # resources/lang/fr.json
2 parents 75a0396 + 25737fa commit e4eb1c3

11 files changed

Lines changed: 144 additions & 19 deletions

File tree

.github/workflows/pr-title.yml

Lines changed: 53 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,56 @@ jobs:
88
pr-title:
99
runs-on: ubuntu-latest
1010
steps:
11-
- uses: deepakputhraya/action-pr-title@master
12-
with:
13-
regex: '^\[\d+\.x\]\s'
11+
- name: Validate PR title matches target branch
12+
env:
13+
PR_TITLE: ${{ github.event.pull_request.title }}
14+
BASE_BRANCH: ${{ github.event.pull_request.base.ref }}
15+
DEFAULT_BRANCH: ${{ github.event.repository.default_branch }}
16+
run: |
17+
# Validates PR title against target branch
18+
# Returns error message if invalid, empty string if valid
19+
validate_pr_title() {
20+
local target_branch="$1"
21+
local pr_title="$2"
22+
local default_branch="$3"
23+
24+
# Check if target branch is a version branch (e.g., 5.x, 4.x)
25+
if [[ $target_branch =~ ^([0-9]+)\.x$ ]]; then
26+
local version="${BASH_REMATCH[1]}"
27+
if [[ ! $pr_title =~ ^\[$version\.x\][[:space:]] ]]; then
28+
echo "PR targeting '$target_branch' must have title starting with '[$version.x] '"
29+
return
30+
fi
31+
32+
# Check if target branch is master (next major version)
33+
elif [[ $target_branch == "master" ]]; then
34+
local current_version="${default_branch//\.x/}"
35+
local next_version=$((current_version + 1))
36+
if [[ ! $pr_title =~ ^\[$next_version\.x\][[:space:]] ]]; then
37+
echo "PR targeting 'master' must have title starting with '[$next_version.x] '"
38+
return
39+
fi
40+
41+
# For other branches, just enforce that there's a version prefix
42+
else
43+
if [[ ! $pr_title =~ ^\[[0-9]+\.x\][[:space:]] ]]; then
44+
echo "PR title must start with a version prefix like '[5.x] '"
45+
return
46+
fi
47+
fi
48+
49+
echo ""
50+
}
51+
52+
echo "PR Title: $PR_TITLE"
53+
echo "Base Branch: $BASE_BRANCH"
54+
echo "Default Branch: $DEFAULT_BRANCH"
55+
56+
ERROR=$(validate_pr_title "$BASE_BRANCH" "$PR_TITLE" "$DEFAULT_BRANCH")
57+
58+
if [[ -n $ERROR ]]; then
59+
echo $ERROR
60+
exit 1
61+
fi
62+
63+
echo "PR title validation passed"

src/Console/Commands/ImportUsers.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,8 @@ private function importUsers()
7777
app()->bind(UserRepositoryContract::class, FileRepository::class);
7878
app()->bind(Passkey::class, FilePasskey::class);
7979

80+
User::clearResolvedInstances();
81+
8082
$users = User::all();
8183

8284
if ($users->isEmpty()) {

src/Http/Controllers/CP/Collections/ExtractsFromEntryFields.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ protected function extractFromFields($entry, $blueprint)
3030
}
3131

3232
$fields = $blueprint
33+
->setParent($entry)
3334
->fields()
3435
->addValues($values)
3536
->preProcess();

src/Listeners/Concerns/GetsItemsContainingData.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,12 @@
77
use Statamic\Facades\GlobalSet;
88
use Statamic\Facades\Term;
99
use Statamic\Facades\User;
10+
use Statamic\Support\Traits\Hookable;
1011

1112
trait GetsItemsContainingData
1213
{
14+
use Hookable;
15+
1316
/**
1417
* Get items containing data.
1518
*
@@ -30,6 +33,9 @@ public function getItemsContainingData()
3033
LazyCollection::make(function () {
3134
yield from User::query()->lazy();
3235
}),
36+
LazyCollection::make(function () {
37+
yield from ($this->runHooks('additional') ?? LazyCollection::make());
38+
}),
3339
];
3440

3541
return LazyCollection::make(function () use ($collections) {
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?php
2+
3+
namespace Statamic\Listeners;
4+
5+
use Statamic\Events\AssetContainerCreated;
6+
use Statamic\Events\CollectionCreated;
7+
use Statamic\Events\GlobalSetCreated;
8+
use Statamic\Events\NavCreated;
9+
use Statamic\Events\Subscriber;
10+
use Statamic\Events\TaxonomyCreated;
11+
use Statamic\Facades\CP\Nav;
12+
13+
class InvalidateNavCache extends Subscriber
14+
{
15+
protected $listeners = [
16+
CollectionCreated::class => 'invalidate',
17+
NavCreated::class => 'invalidate',
18+
TaxonomyCreated::class => 'invalidate',
19+
AssetContainerCreated::class => 'invalidate',
20+
GlobalSetCreated::class => 'invalidate',
21+
];
22+
23+
public function invalidate($event): void
24+
{
25+
Nav::clearCachedUrls();
26+
}
27+
}

src/Providers/EventServiceProvider.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ class EventServiceProvider extends ServiceProvider
3737
\Statamic\Listeners\GeneratePresetImageManipulations::class,
3838
\Statamic\Listeners\UpdateAssetReferences::class,
3939
\Statamic\Listeners\UpdateTermReferences::class,
40+
\Statamic\Listeners\InvalidateNavCache::class,
4041
];
4142

4243
public function register()

src/Stache/Query/Builder.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -157,19 +157,19 @@ protected function filterWhereBasic($values, $where)
157157

158158
protected function filterWhereIn($values, $where)
159159
{
160-
$lookup = array_flip($where['values']);
160+
$lookup = array_flip(array_map(fn ($v) => $v ?? '__NULL__', $where['values']));
161161

162162
return $values->filter(
163-
fn ($value) => isset($lookup[$value])
163+
fn ($value) => isset($lookup[$value ?? '__NULL__'])
164164
);
165165
}
166166

167167
protected function filterWhereNotIn($values, $where)
168168
{
169-
$lookup = array_flip($where['values']);
169+
$lookup = array_flip(array_map(fn ($v) => $v ?? '__NULL__', $where['values']));
170170

171171
return $values->filter(
172-
fn ($value) => ! isset($lookup[$value])
172+
fn ($value) => ! isset($lookup[$value ?? '__NULL__'])
173173
);
174174
}
175175

tests/CP/Navigation/ActiveNavItemTest.php

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -110,17 +110,9 @@ public function it_updates_caches_when_new_child_urls_are_detected_after_resolvi
110110
// Now let's create a new collection
111111
Facades\Collection::make('products')->title('Products')->save();
112112

113-
// Simply building the nav should change what is cached
114-
$collectionsChildrenUrls = [
115-
'http://localhost/cp/collections/articles',
116-
'http://localhost/cp/collections/pages',
117-
];
118-
$this->assertEquals($collectionsChildrenUrls, Cache::get(NavBuilder::UNRESOLVED_CHILDREN_URLS_CACHE_KEY)->get('content::collections'));
119-
$this->assertEquals($collectionsChildrenUrls, Blink::get(NavBuilder::UNRESOLVED_CHILDREN_URLS_CACHE_KEY)->get('content::collections'));
120-
collect($collectionsChildrenUrls)->each(function ($url) {
121-
$this->assertTrue(Cache::get(NavBuilder::ALL_URLS_CACHE_KEY)->contains($url));
122-
$this->assertTrue(Blink::get(NavBuilder::ALL_URLS_CACHE_KEY)->contains($url));
123-
});
113+
// The InvalidateNavCache subscriber will clear the URLs cache.
114+
$this->assertNull(Cache::get(NavBuilder::UNRESOLVED_CHILDREN_URLS_CACHE_KEY));
115+
$this->assertNull(Blink::get(NavBuilder::UNRESOLVED_CHILDREN_URLS_CACHE_KEY));
124116

125117
// But if we build the nav again by hitting collections url to resolve its' children, the caches should get updated
126118
$this

tests/Data/Entries/EntryQueryBuilderTest.php

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,36 @@ public function entries_are_found_using_or_where_not_in()
9292
$this->assertEquals(['Post 3', 'Post 4'], $entries->map->title->all());
9393
}
9494

95+
#[Test]
96+
public function entries_are_found_using_where_in_with_null()
97+
{
98+
EntryFactory::id('1')->slug('post-1')->collection('posts')->data(['title' => 'Post 1', 'category' => 'news'])->create();
99+
EntryFactory::id('2')->slug('post-2')->collection('posts')->data(['title' => 'Post 2', 'category' => 'blog'])->create();
100+
EntryFactory::id('3')->slug('post-3')->collection('posts')->data(['title' => 'Post 3'])->create(); // category is null
101+
EntryFactory::id('4')->slug('post-4')->collection('posts')->data(['title' => 'Post 4', 'category' => 'news'])->create();
102+
EntryFactory::id('5')->slug('post-5')->collection('posts')->data(['title' => 'Post 5'])->create(); // category is null
103+
104+
$entries = Entry::query()->whereIn('category', ['news', null])->get();
105+
106+
$this->assertCount(4, $entries);
107+
$this->assertEquals(['Post 1', 'Post 3', 'Post 4', 'Post 5'], $entries->map->title->all());
108+
}
109+
110+
#[Test]
111+
public function entries_are_found_using_where_not_in_with_null()
112+
{
113+
EntryFactory::id('1')->slug('post-1')->collection('posts')->data(['title' => 'Post 1', 'category' => 'news'])->create();
114+
EntryFactory::id('2')->slug('post-2')->collection('posts')->data(['title' => 'Post 2', 'category' => 'blog'])->create();
115+
EntryFactory::id('3')->slug('post-3')->collection('posts')->data(['title' => 'Post 3'])->create(); // category is null
116+
EntryFactory::id('4')->slug('post-4')->collection('posts')->data(['title' => 'Post 4', 'category' => 'news'])->create();
117+
EntryFactory::id('5')->slug('post-5')->collection('posts')->data(['title' => 'Post 5'])->create(); // category is null
118+
119+
$entries = Entry::query()->whereNotIn('category', ['news', null])->get();
120+
121+
$this->assertCount(1, $entries);
122+
$this->assertEquals(['Post 2'], $entries->map->title->all());
123+
}
124+
95125
#[Test]
96126
public function entries_are_found_using_where_date()
97127
{

tests/Listeners/UpdateAssetReferencesTest.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,12 @@
44

55
use Illuminate\Support\Facades\Cache;
66
use Illuminate\Support\Facades\Storage;
7+
use Illuminate\Support\LazyCollection;
78
use Orchestra\Testbench\Attributes\DefineEnvironment;
89
use PHPUnit\Framework\Attributes\Test;
910
use Statamic\Assets\AssetFolder;
1011
use Statamic\Facades;
12+
use Statamic\Listeners\UpdateAssetReferences;
1113
use Statamic\Support\Arr;
1214
use Tests\PreventSavingStacheItemsToDisk;
1315
use Tests\TestCase;
@@ -1850,6 +1852,19 @@ public function it_only_saves_items_when_there_is_something_to_update()
18501852
$this->assetHoff->path('hoff-new.jpg')->save();
18511853
}
18521854

1855+
#[Test]
1856+
public function it_gets_items_from_a_hook()
1857+
{
1858+
UpdateAssetReferences::hook('additional', function () {
1859+
return LazyCollection::make(['additional-1', 'additional-2']);
1860+
});
1861+
1862+
$items = ((new UpdateAssetReferences)->getItemsContainingData())->all();
1863+
1864+
$this->assertContains('additional-1', $items);
1865+
$this->assertContains('additional-2', $items);
1866+
}
1867+
18531868
protected function setSingleBlueprint($namespace, $blueprintContents)
18541869
{
18551870
$blueprint = tap(Facades\Blueprint::make('single-blueprint')->setContents($blueprintContents))->save();

0 commit comments

Comments
 (0)