Skip to content

Commit ba76084

Browse files
authored
Merge branch 'tempestphp:main' into read-file-locking
2 parents 3d517d8 + c7292e2 commit ba76084

File tree

172 files changed

+4484
-310
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

172 files changed

+4484
-310
lines changed

.github/workflows/integration-tests.yml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,10 @@ jobs:
8989
- name: Install dependencies
9090
run: composer update --${{ matrix.stability }} --prefer-dist --no-interaction
9191

92+
- name: "Setup Redis"
93+
if: ${{ matrix.os != 'windows-latest' }}
94+
uses: supercharge/[email protected]
95+
9296
- name: "Setup MySQL"
9397
if: ${{ matrix.database == 'mysql' }}
9498
uses: ankane/setup-mysql@v1
@@ -104,7 +108,7 @@ jobs:
104108
run: php -r "copy('tests/Fixtures/Config/database.${{ matrix.database }}.php', 'tests/Fixtures/Config/database.config.php');"
105109

106110
- name: Tempest about
107-
run: php ./tempest about
111+
run: php ./tempest about -v
108112

109113
- name: List discovered locations
110114
run: php ./tempest discovery:status

CHANGELOG.md

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,47 @@
22

33
All notable changes to this project will be documented in this file.
44

5-
## [1.2.2](https://github.com/tempestphp/tempest-framework/compare/v1.2.1..1.2.2) — 2025-07-08
5+
## [1.4.0](https://github.com/tempestphp/tempest-framework/compare/v1.3.1..1.4.0) — 2025-07-17
6+
7+
### 🚀 Features
8+
9+
- **auth**: add class-level permission support (#1405) ([1404246](https://github.com/tempestphp/tempest-framework/commit/14042463f81e6915a61212abaf468a351ca5b2b9))
10+
- **mailer**: introduce mailer component (#1227) ([3f5f31e](https://github.com/tempestphp/tempest-framework/commit/3f5f31eacfc80a6ba8ac724f042eefd5cf8e6412))
11+
- **support**: add json encode/decode to array and string utilities (#1396) ([978bba2](https://github.com/tempestphp/tempest-framework/commit/978bba2d3f5017c4c90920d272c2c3d143aa2485))
12+
- **vite**: inject react refresh when needed (#1406) ([b57bf7f](https://github.com/tempestphp/tempest-framework/commit/b57bf7f9c79179f7135c1eb72894406d80d6a606))
13+
14+
### 🐛 Bug fixes
15+
16+
- **mail**: fix typos (#1410) ([0e29b0e](https://github.com/tempestphp/tempest-framework/commit/0e29b0e83be94a968d4f004d87191ad70b385f3d))
17+
- **mailer**: small tweaks and bugfixes (#1408) ([f80536a](https://github.com/tempestphp/tempest-framework/commit/f80536a5ba5784978df9cad9cc8453be564b0110))
18+
- **vite**: exclude `.tempest` from vite's file watcher (#1384) ([e1bdcf2](https://github.com/tempestphp/tempest-framework/commit/e1bdcf2daedcdd2076b33048de2bcd963a403dca))
19+
20+
21+
## [1.3.0](https://github.com/tempestphp/tempest-framework/compare/v1.2.3..v1.3.0) — 2025-07-10
22+
23+
### 🚀 Features
24+
25+
- **database**: run `migrate:fresh` without validation by default (#1390) ([665c825](https://github.com/tempestphp/tempest-framework/commit/665c825230a6803e0e52a64d08c28623aa267b48))
26+
27+
### 🐛 Bug fixes
28+
29+
- **commandbus**: require console as a dependency (#1397) ([e56cb6d](https://github.com/tempestphp/tempest-framework/commit/e56cb6d72678e632c413c01ba7dc317396f1e7ba))
30+
- **router**: change the `Bindable::resolve` return type from `static` to `self` (#1391) ([3ac0e3a](https://github.com/tempestphp/tempest-framework/commit/3ac0e3aa0489ecd57e0d7dbe23c7e84ad392bfa2))
31+
- **view**: remove multiline comments before AST parsing (#1395) ([f2c03df](https://github.com/tempestphp/tempest-framework/commit/f2c03df89977fdf0008b40c1777f31cde91108ca))
32+
33+
### 🚜 Refactor
34+
35+
- **mapper**: remove redundant string check (#1393) ([9d0bf46](https://github.com/tempestphp/tempest-framework/commit/9d0bf46854e55eb22b9572847c8e000bddd3a2e3))
36+
37+
38+
## [1.2.3](https://github.com/tempestphp/tempest-framework/compare/v1.2.2..v1.2.3) — 2025-07-08
39+
40+
### 🐛 Bug fixes
41+
42+
- **database**: fix datetime serialization for mysql database (#1383) ([dde0e84](https://github.com/tempestphp/tempest-framework/commit/dde0e84a6bba614c4fa3932914ffaee2dd4916e7))
43+
44+
45+
## [1.2.2](https://github.com/tempestphp/tempest-framework/compare/v1.2.1..v1.2.2) — 2025-07-08
646

747
### 🚀 Features
848

bin/release

Lines changed: 50 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use Composer\Semver\VersionParser;
1818
use Tempest\Console\Console;
1919
use Tempest\Console\ConsoleApplication;
2020
use Tempest\Console\Exceptions\InterruptException;
21-
use Tempest\Http\Status;
21+
use Tempest\Http\Response;
2222
use Tempest\HttpClient\HttpClient;
2323
use Tempest\Support\Json;
2424

@@ -168,28 +168,51 @@ function performPreReleaseChecks(string $remote, string $branch): void
168168
}
169169
}
170170

171-
/**
171+
/**
172172
* Disables the protection ruleset, so the release branch can be pushed to without a pull request.
173173
*/
174174
function updateBranchProtection(bool $enabled): void
175175
{
176176
// https://github.com/tempestphp/tempest-framework/settings/rules/1879240
177177
$ruleset = '1879240';
178178
$token = Tempest\env('RELEASE_GITHUB_TOKEN');
179-
$url = "https://api.github.com/repos/tempestphp/tempest-framework/rulesets/{$ruleset}";
179+
$uri = "https://api.github.com/repos/tempestphp/tempest-framework/rulesets/{$ruleset}";
180180

181181
$httpClient = Tempest\get(HttpClient::class);
182182
$response = $httpClient->put(
183-
uri: $url,
183+
uri: $uri,
184184
headers: ['Authorization' => "Bearer {$token}"],
185-
body: Json\encode(['enforcement' => $enabled ? 'active' : 'disabled'])
185+
body: Json\encode(['enforcement' => $enabled ? 'active' : 'disabled']),
186186
);
187187

188-
if ($response->status !== Status::OK) {
188+
if (! $response->status->isSuccessful()) {
189189
throw new Exception('Failed to update branch ruleset.');
190190
}
191191
}
192192

193+
function triggerSubsplit(): void
194+
{
195+
$token = Tempest\env('RELEASE_GITHUB_TOKEN');
196+
$uri = 'https://api.github.com/repos/tempestphp/tempest-framework/actions/workflows/subsplit-packages.yml/dispatches';
197+
198+
$httpClient = Tempest\get(HttpClient::class);
199+
200+
$response = $httpClient->post(
201+
uri: $uri,
202+
headers: [
203+
'Authorization' => "Bearer {$token}",
204+
'Accept' => 'application/vnd.github+json',
205+
'X-GitHub-Api-Version' => '2022-11-28',
206+
],
207+
body: Json\encode(['ref' => 'main']),
208+
);
209+
210+
if (! $response->status->isSuccessful()) {
211+
throw new Exception('Failed to update branch ruleset.');
212+
}
213+
}
214+
215+
193216
/**
194217
* Gets the current version.
195218
*/
@@ -210,9 +233,9 @@ function suggestNextVersions(string $current): array
210233
}
211234

212235
$isStable = ! isset($matches[4]);
213-
$major = (int) $matches[1];
214-
$minor = (int) $matches[2];
215-
$patch = (int) $matches[3];
236+
$major = (int)$matches[1];
237+
$minor = (int)$matches[2];
238+
$patch = (int)$matches[3];
216239

217240
// Current version is stable
218241
if ($isStable) {
@@ -280,8 +303,8 @@ function updateJsonFile(string $path, Closure $callback): void
280303
$content = $callback(json_decode($content, associative: true), $indent);
281304
$content = preg_replace_callback(
282305
'/^ +/m',
283-
fn ($m) => str_repeat($indent, \strlen($m[0]) / 4),
284-
json_encode($content, \JSON_PRETTY_PRINT | \JSON_UNESCAPED_SLASHES),
306+
fn ($m) => str_repeat($indent, strlen($m[0]) / 4),
307+
json_encode($content, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES),
285308
);
286309

287310
file_put_contents($path, $content . "\n");
@@ -329,13 +352,13 @@ try {
329352
$new = $console->ask(
330353
question: 'What should the new version be?',
331354
options: arr(suggestNextVersions($current))
332-
->map(fn (string $version, string $type) => (string) str($type)->replace('_', ' ')->append(': ', $version))
355+
->map(fn (string $version, string $type) => (string)str($type)->replace('_', ' ')->append(': ', $version))
333356
->values()
334357
->toArray(),
335358
);
336359

337360
$isMajor = str_contains($new, 'major');
338-
$version = (string) str($new)->afterLast(': ');
361+
$version = (string)str($new)->afterLast(': ');
339362
$tag = "v{$version}";
340363

341364
// Check the tag
@@ -349,10 +372,10 @@ try {
349372
// Bump PHP packages
350373
$console->task(
351374
label: 'Bumping PHP packages',
352-
handler: fn () => [
353-
bumpKernelVersion($version),
354-
bumpPhpPackages($version, $isMajor),
355-
],
375+
handler: function () use ($version, $isMajor) {
376+
bumpKernelVersion($version);
377+
bumpPhpPackages($version, $isMajor);
378+
},
356379
);
357380

358381
// Bump JavaScript packages
@@ -373,27 +396,27 @@ try {
373396
// Push tags
374397
$console->task(
375398
label: 'Releasing',
376-
handler: fn () => [
377-
commit("chore: release {$tag}"),
399+
handler: function () use ($tag) {
400+
commit("chore: release {$tag}");
378401
executeCommands([
379402
"git tag {$tag}",
380403
"git push origin tag {$tag}",
381-
]),
382-
],
404+
]);
405+
},
383406
);
384407

385408
// Clean up
386409
$console->task(
387410
label: 'Cleaning up',
388-
handler: fn () => [
389-
cleanUpAfterRelease(),
390-
commit('chore: post-release clean up'),
391-
executeCommands('git push'),
392-
],
411+
handler: function () {
412+
cleanUpAfterRelease();
413+
commit('chore: post-release clean up');
414+
executeCommands('git push');
415+
},
393416
);
394417

395-
// Re-enable protection
396418
updateBranchProtection(enabled: true);
419+
triggerSubsplit();
397420

398421
$console->success(sprintf(
399422
'Released <em>%1$s</em>. The <href="https://github.com/tempestphp/tempest-framework/releases/tag/%1$s">GitHub release</href> will be created automatically in a few seconds.',

bin/validate-packages

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ function checkPackageLicense(array $package): void
3333

3434
if (! file_exists($licenseFile)) {
3535
throw new UnexpectedValueException(
36-
sprintf('Package [tempest/%s] is missing it\'s license.', $package['name'])
36+
sprintf('Package [tempest/%s] is missing it\'s license (%s).', $package['name'], $licenseFile)
3737
);
3838
}
3939

composer.json

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
"psr/http-message": "^1.0|^2.0",
3232
"psr/log": "^3.0.0",
3333
"symfony/cache": "^7.2",
34+
"symfony/mailer": "^7.2.6",
3435
"symfony/process": "^7.1",
3536
"symfony/uid": "^7.1",
3637
"symfony/var-dumper": "^7.1",
@@ -62,9 +63,12 @@
6263
"phpbench/phpbench": "84.x-dev",
6364
"phpstan/phpstan": "^2.0",
6465
"phpunit/phpunit": "^12.2.3",
66+
"predis/predis": "^3.0.0",
6567
"rector/rector": "^2.0-rc2",
6668
"spatie/phpunit-snapshot-assertions": "^5.1.8",
6769
"spaze/phpstan-disallowed-calls": "^4.0",
70+
"symfony/amazon-mailer": "^7.2.0",
71+
"symfony/postmark-mailer": "^7.2.6",
6872
"symplify/monorepo-builder": "^11.2",
6973
"tempest/blade": "^0.1.0",
7074
"twig/twig": "^3.16"
@@ -87,7 +91,9 @@
8791
"tempest/http-client": "self.version",
8892
"tempest/icon": "self.version",
8993
"tempest/intl": "self.version",
94+
"tempest/kv-store": "self.version",
9095
"tempest/log": "self.version",
96+
"tempest/mail": "self.version",
9197
"tempest/mapper": "self.version",
9298
"tempest/reflection": "self.version",
9399
"tempest/router": "self.version",
@@ -123,7 +129,9 @@
123129
"Tempest\\Http\\": "packages/http/src",
124130
"Tempest\\Icon\\": "packages/icon/src",
125131
"Tempest\\Intl\\": "packages/intl/src",
132+
"Tempest\\KeyValue\\": "packages/kv-store/src",
126133
"Tempest\\Log\\": "packages/log/src",
134+
"Tempest\\Mail\\": "packages/mail/src",
127135
"Tempest\\Mapper\\": "packages/mapper/src",
128136
"Tempest\\Reflection\\": "packages/reflection/src",
129137
"Tempest\\Router\\": "packages/router/src",
@@ -143,6 +151,7 @@
143151
"packages/datetime/src/functions.php",
144152
"packages/debug/src/functions.php",
145153
"packages/event-bus/src/functions.php",
154+
"packages/http/src/functions.php",
146155
"packages/icon/src/functions.php",
147156
"packages/intl/src/Number/functions.php",
148157
"packages/intl/src/functions.php",
@@ -183,7 +192,9 @@
183192
"Tempest\\Http\\Tests\\": "packages/http/tests",
184193
"Tempest\\Icon\\Tests\\": "packages/icon/tests",
185194
"Tempest\\Intl\\Tests\\": "packages/intl/tests",
195+
"Tempest\\KeyValue\\Tests\\": "packages/kv-store/tests",
186196
"Tempest\\Log\\Tests\\": "packages/log/tests",
197+
"Tempest\\Mail\\Tests\\": "packages/mail/tests",
187198
"Tempest\\Mapper\\Tests\\": "packages/mapper/tests",
188199
"Tempest\\Reflection\\Tests\\": "packages/reflection/tests",
189200
"Tempest\\Router\\Tests\\": "packages/router/tests",

packages/auth/src/Allow.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
use Attribute;
88
use UnitEnum;
99

10-
#[Attribute(Attribute::TARGET_METHOD)]
10+
#[Attribute(Attribute::TARGET_CLASS | Attribute::TARGET_METHOD)]
1111
final readonly class Allow
1212
{
1313
public function __construct(

packages/auth/src/AuthorizerMiddleware.php

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,11 @@ public function __construct(
2424

2525
public function __invoke(Request $request, HttpMiddlewareCallable $next): Response
2626
{
27-
$attribute = $this->matchedRoute
27+
$handler = $this->matchedRoute
2828
->route
29-
->handler
30-
->getAttribute(Allow::class);
29+
->handler;
30+
31+
$attribute = $handler->getAttribute(Allow::class) ?? $handler->getDeclaringClass()->getAttribute(Allow::class);
3132

3233
if ($attribute === null) {
3334
return $next($request);

packages/cache/composer.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
"symfony/cache": "^7.2",
88
"tempest/core": "dev-main",
99
"tempest/clock": "dev-main",
10+
"tempest/kv-store": "dev-main",
1011
"tempest/container": "dev-main"
1112
},
1213
"require-dev": {

packages/cache/src/CacheInitializer.php

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,13 @@ public function canInitialize(ClassReflector $class, null|string|UnitEnum $tag):
2525
#[Singleton]
2626
public function initialize(ClassReflector $class, null|string|UnitEnum $tag, Container $container): Cache
2727
{
28+
$config = $container->get(CacheConfig::class, $tag);
29+
2830
return new GenericCache(
29-
cacheConfig: $container->get(CacheConfig::class, $tag),
30-
deferredTasks: $container->get(DeferredTasks::class),
31+
adapter: $config->createAdapter($container),
3132
enabled: $this->shouldCacheBeEnabled($tag),
33+
deferredTasks: $container->get(DeferredTasks::class),
34+
tag: $tag,
3235
);
3336
}
3437

packages/cache/src/Commands/CacheStatusCommand.php

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -99,12 +99,10 @@ private function getCacheName(Cache $cache): string
9999
return $cache::class;
100100
}
101101

102-
$tag = $cache->cacheConfig->tag;
103-
104-
if ($tag instanceof UnitEnum) {
105-
return $tag->name;
102+
if ($cache->tag instanceof UnitEnum) {
103+
return $cache->tag->name;
106104
}
107105

108-
return $tag ?? 'default';
106+
return $cache->tag ?? 'default';
109107
}
110108
}

0 commit comments

Comments
 (0)