Skip to content

Commit efaf9c6

Browse files
committed
Merge branch 'main' into test-class-style-fallthrough
2 parents 7bc087c + 814ddd4 commit efaf9c6

File tree

212 files changed

+2791
-408
lines changed

Some content is hidden

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

212 files changed

+2791
-408
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ packages/database.sqlite
1414
packages/database/src/database.sqlite
1515
src/Tempest/database.sqlite
1616
tests/Fixtures/database.sqlite
17+
tests/Fixtures/database*.sqlite
1718
tests/Unit/Console/test-console.log
1819
src/Tempest/Database/src/database.sqlite
1920
.env

CHANGELOG.md

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,74 @@
22

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

5+
## [2.13.0](https://github.com/tempestphp/tempest-framework/compare/v2.12.0..2.13.0) — 2025-12-04
6+
7+
### 🚀 Features
8+
9+
- **auth**: add OAuth installer (#1674) ([9c82b71](https://github.com/tempestphp/tempest-framework/commit/9c82b715b448633a704591e9b78823da28debc98))
10+
- **cache**: make `assertLocked` ensure that the checked lock has an expiration (#1758) ([1a2e8fb](https://github.com/tempestphp/tempest-framework/commit/1a2e8fbe90259d2bd5a8a0876d4b8fed35c5dcd7))
11+
- **container**: make all container properties publicly readable (#1785) ([be93ec1](https://github.com/tempestphp/tempest-framework/commit/be93ec1388ec7d253637705d4335d13a78a39f00))
12+
- **database**: add support for self-referencing relations (#1745) ([df2dcdc](https://github.com/tempestphp/tempest-framework/commit/df2dcdc231384d2dd359f8b621f0ae1f31a3e703))
13+
- **http**: add support to mark Request properties as #[SensitiveField] (#1746) ([0000c99](https://github.com/tempestphp/tempest-framework/commit/0000c99251b31d0bfa84389fb101be1560d916c3))
14+
15+
### 🐛 Bug fixes
16+
17+
- **auth**: correctly map user in GitHub OAuth provider (#1751) ([ad2182a](https://github.com/tempestphp/tempest-framework/commit/ad2182ac40684b78752e7f7511228688f5093c1a))
18+
- **auth**: pass scopes/options to auth URL builder (#1750) ([cbe54d7](https://github.com/tempestphp/tempest-framework/commit/cbe54d7f3f7e137fe43e9ad7f8837bd2f7103e9a))
19+
- **auth**: update outdated authenticatable import (#1752) ([5c68b96](https://github.com/tempestphp/tempest-framework/commit/5c68b968763229dfb5a78c01a80df3b1b134e6c0))
20+
- **cache**: support enum tags (#1756) ([678b695](https://github.com/tempestphp/tempest-framework/commit/678b69582e526e25ff545c346179bda9636f1415))
21+
- **cache**: add descriptions to `cache:clear` arguments (#1755) ([e324f6e](https://github.com/tempestphp/tempest-framework/commit/e324f6e767b50acd6e76e8310be12422b85e782b))
22+
- **command-bus**: extract uuid from pending commands when not provided (#1761) ([b787c16](https://github.com/tempestphp/tempest-framework/commit/b787c16e57f60de3bd7883944561f02fce3a661a))
23+
- **console**: properly normalize boolean flag names (#1762) ([c6e6867](https://github.com/tempestphp/tempest-framework/commit/c6e6867ede678b9798386bab12e1e2afaef91bc8))
24+
- **core**: gracefully handle missing seeders when using `db:seed` (#1759) ([450ca75](https://github.com/tempestphp/tempest-framework/commit/450ca7576c6e5a8f4f5719dd27e7d4d4a29954c9))
25+
- **process**: properly return exit code if missing (#1776) ([9ad1587](https://github.com/tempestphp/tempest-framework/commit/9ad158747a810db490aef43a7a6c1bcfe062d900))
26+
27+
28+
## [2.12.0](https://github.com/tempestphp/tempest-framework/compare/v2.11.0..v2.12.0) — 2025-11-28
29+
30+
### 🚀 Features
31+
32+
- **eventbus**: add `#[StopsPropagation]` (#1740) ([5769ec2](https://github.com/tempestphp/tempest-framework/commit/5769ec215d96b4dbdac9a3e2fb93f97de152fca5))
33+
- **validation**: support nullable enums (#1739) ([a9ca8c4](https://github.com/tempestphp/tempest-framework/commit/a9ca8c4d60aca0ba4e14d0c31ce056c02415c10e))
34+
35+
### 🐛 Bug fixes
36+
37+
- **core**: remove php 8.5 deprecations (#1742) ([7501c1b](https://github.com/tempestphp/tempest-framework/commit/7501c1b494a2ec2e5ee27f4a8407fbdef5e484ae))
38+
- **support**: correct some string function oversights (#1743) ([f113128](https://github.com/tempestphp/tempest-framework/commit/f113128d71bd5fd10568f9cc07a86732f4e6a116))
39+
- **support**: process error message after callback in box() (#1741) ([908352a](https://github.com/tempestphp/tempest-framework/commit/908352a81969be7d4652b1c62758261b4751ee35))
40+
41+
42+
## [2.11.0](https://github.com/tempestphp/tempest-framework/compare/v2.10.0..v2.11.0) — 2025-11-26
43+
44+
### 🚀 Features
45+
46+
- **core**: partial discovery loading (#1737) ([92a31c3](https://github.com/tempestphp/tempest-framework/commit/92a31c3a2ccfecbea1b0ffdf0f212af23d0b36a7))
47+
48+
49+
## [2.10.0](https://github.com/tempestphp/tempest-framework/compare/v2.9.3..v2.10.0) — 2025-11-26
50+
51+
### 🚀 Features
52+
53+
- **core**: load composer dev namespaces (#1736) ([892da0c](https://github.com/tempestphp/tempest-framework/commit/892da0ce1a2b0b0b44a4b48121c4a3d7dc3e862d))
54+
- **database**: add ability to create a query builder from another one (#1725) ([55204a0](https://github.com/tempestphp/tempest-framework/commit/55204a05c2d69ca3376d74cb795be6fb389e28a4))
55+
- **tests**: support paratest (#1721) ([f5b5cd3](https://github.com/tempestphp/tempest-framework/commit/f5b5cd3f61c0d49fdeb38f97d6de861893ac4cbc))
56+
- **view**: fixes PHP 8.5 null offset deprecation warning (#1729) ([2349c71](https://github.com/tempestphp/tempest-framework/commit/2349c71f960f3638bed89f703d282c451b4536b8))
57+
58+
59+
## [2.9.3](https://github.com/tempestphp/tempest-framework/compare/v2.9.2..v2.9.3) — 2025-11-20
60+
61+
### 🐛 Bug fixes
62+
63+
- **router**: use route registry to generate uris (#1724) ([6dc51c2](https://github.com/tempestphp/tempest-framework/commit/6dc51c29e40092379f918e6f3bd47862c2e090d1))
64+
65+
66+
## [2.9.2](https://github.com/tempestphp/tempest-framework/compare/v2.9.1..v2.9.2) — 2025-11-19
67+
68+
### 🐛 Bug fixes
69+
70+
- **intl**: make pluralizer singleton (#1726) ([39b2b2d](https://github.com/tempestphp/tempest-framework/commit/39b2b2da8683a1d08b5ebabcd71f35486a85e403))
71+
72+
573
## [2.9.0](https://github.com/tempestphp/tempest-framework/compare/v2.8.0..v2.9.0) — 2025-11-14
674

775
### 🚀 Features

composer.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
"adam-paterson/oauth2-slack": "^1.1",
5050
"aws/aws-sdk-php": "^3.338.0",
5151
"azure-oss/storage-blob-flysystem": "^1.2",
52+
"brianium/paratest": "^7.14",
5253
"carthage-software/mago": "1.0.0-beta.28",
5354
"depotwarehouse/oauth2-twitch": "^1.3",
5455
"guzzlehttp/psr7": "^2.6.1",
@@ -246,6 +247,8 @@
246247
"coverage": "vendor/bin/phpunit --coverage-html build/reports/html --coverage-clover build/reports/clover.xml",
247248
"fmt": "vendor/bin/mago fmt",
248249
"lint:fix": "vendor/bin/mago lint --fix --format-after-fix",
250+
"style": "composer fmt && composer lint:fix",
251+
"test": "composer phpunit",
249252
"lint": "vendor/bin/mago lint --potentially-unsafe --minimum-fail-level=note",
250253
"phpstan": "vendor/bin/phpstan analyse src tests --memory-limit=1G",
251254
"rector": "vendor/bin/rector process --no-ansi",

docs/1-essentials/01-routing.md

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -175,9 +175,9 @@ final class Aircraft implements Bindable
175175
{
176176
use IsDatabaseModel;
177177

178-
public function resolve(string $input): self
178+
public static function resolve(string $input): self
179179
{
180-
return self::find(id: $input);
180+
return self::findById(id: $input);
181181
}
182182
}
183183
```
@@ -193,9 +193,9 @@ final class Aircraft implements Bindable
193193
#[IsBindingValue]
194194
public string $callSign;
195195

196-
public function resolve(string $input): self
196+
public static function resolve(string $input): self
197197
{
198-
return self::find(id: $input);
198+
return self::findById(id: $input);
199199
}
200200
}
201201
```
@@ -241,7 +241,7 @@ public function docsRedirect(string $path): Redirect
241241

242242
## Generating URIs
243243

244-
Tempest provides a `\Tempest\uri` function that can be used to generate a URI to a controller method. This function accepts the FQCN of the controller or a callable to a method as its first argument, and named parameters as [the rest of its arguments](https://www.php.net/manual/en/functions.arguments.php#functions.variable-arg-list).
244+
Tempest provides a `\Tempest\Router\uri` function that can be used to generate a URI to a controller method. This function accepts the FQCN of the controller or a callable to a method as its first argument, and named parameters as [the rest of its arguments](https://www.php.net/manual/en/functions.arguments.php#functions.variable-arg-list).
245245

246246
```php
247247
use function Tempest\Router\uri;
@@ -337,7 +337,7 @@ A core pattern of any web application is to access data from the current request
337337

338338
In most situations, the data you expect to receive from a request is structured. You expect clients to send specific values, and you want them to follow specific rules.
339339

340-
The idiomatic way to achieve this is by using request classes. They are classes with public properties that correspond to the data you want to retrieve from the request. Tempest will automatically validate these properties using PHP's type system, in addition to optional [validation attributes](../2-features/06-validation) if needed.
340+
The idiomatic way to achieve this is by using request classes. They are classes with public properties that correspond to the data you want to retrieve from the request. Tempest will automatically validate these properties using PHP's type system, in addition to optional [validation attributes](../2-features/03-validation) if needed.
341341

342342
A request class must implement {`Tempest\Http\Request`} and should use the {`Tempest\Http\IsRequest`} trait, which provides the default implementation.
343343

@@ -387,6 +387,33 @@ final readonly class AirportController
387387
The `map()` function allows mapping any data from any source into objects of your choice. You may read more about them in [their documentation](../2-features/01-mapper.md).
388388
:::
389389

390+
### Sensitive fields
391+
392+
When handling sensitive data such as passwords or tokens, you may not want these values to be stored in the session or re-displayed in forms after validation errors. You can mark request properties as sensitive using the {b`#[Tempest\Http\SensitiveField]`} attribute:
393+
394+
```php app/ResetPasswordRequest.php
395+
use Tempest\Http\Request;
396+
use Tempest\Http\IsRequest;
397+
use Tempest\Http\SensitiveField;
398+
use Tempest\Validation\Rules\HasMinLength;
399+
400+
final class ResetPasswordRequest implements Request
401+
{
402+
use IsRequest;
403+
404+
public string $email;
405+
406+
#[SensitiveField]
407+
#[HasMinLength(8)]
408+
public string $password;
409+
410+
#[SensitiveField]
411+
public string $password_confirmation;
412+
}
413+
```
414+
415+
When a validation error occurs, Tempest will filter out sensitive fields from the original values stored in the session. This prevents sensitive data from being re-populated in forms after a redirect.
416+
390417
### Retrieving data directly
391418

392419
For simpler use cases, you may simply retrieve a value from the body or the query parameter using the request's `get` method.
@@ -427,7 +454,7 @@ The JSON encoded header is available for when you're building APIs with Tempest.
427454
</x-form>
428455
```
429456

430-
`{html}<x-form>` is a view component that will automatically include the CSRF token, as well as default to sending `POST` requests. `{html}<x-input>` is a view component that renders a label, input field, and validation errors all at once. In practice, you'll likely want to make changes to these built-in view components. That's why you can run `./tempest install view-components` and select the components you want to pull into your project. You can [read more about installing view components here](/2.x/essentials/views#built-in-components).
457+
`{html}<x-form>` is a view component that will automatically include the CSRF token, as well as default to sending `POST` requests. `{html}<x-input>` is a view component that renders a label, input field, and validation errors all at once. In practice, you'll likely want to make changes to these built-in view components. That's why you can run `./tempest install view-components` and select the components you want to pull into your project. You can [read more about installing view components here](../1-essentials/02-views.md#built-in-components).
431458

432459
## Route middleware
433460

@@ -919,7 +946,7 @@ return new DatabaseSessionConfig(
919946

920947
Sessions expire based on the last activity time. This means that as long as a user is actively using your application, their session will remain valid.
921948

922-
Outdated sessions must occasionally be cleaned up. Tempest comes with a built-in command to do so, `session:clean`. This command makes use of the [scheduler](/2.x/features/scheduling). If you have scheduling enabled, it will automatically run behind the scenes.
949+
Outdated sessions must occasionally be cleaned up. Tempest comes with a built-in command to do so, `session:clean`. This command makes use of the [scheduler](../2-features/11-scheduling.md). If you have scheduling enabled, it will automatically run behind the scenes.
923950

924951
## Deferring tasks
925952

docs/1-essentials/02-views.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -502,7 +502,7 @@ This component provides a form element that will post by default and includes th
502502

503503
```html
504504
<?php
505-
use function \Tempest\uri;
505+
use function \Tempest\Router\uri;
506506
?>
507507

508508
<x-form :action="uri(StorePostController::class)">

docs/1-essentials/03-database.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,10 @@ final class Book
219219
}
220220
```
221221

222+
:::warning
223+
Relation types in docblocks must always be fully qualified, and not use short class names.
224+
:::
225+
222226
Tempest will infer all the information it needs to build the right queries for you. However, there might be cases where property names and type information don't map one-to-one on your database schema. In that case you can use dedicated attributes to define relations.
223227

224228
### Relation attributes

docs/2-features/08-events.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,31 @@ final readonly class EventLoggerMiddleware implements EventBusMiddleware
159159
{ /* … */ }
160160
```
161161

162+
## Stopping event propagation
163+
164+
In rare cases you might want an event only to be handled by a single handler. You can use the `b{Tempest\EventBus\StopsPropagation}` attribute on both events and event handlers to achieve this:
165+
166+
```php
167+
use Tempest\EventBus\StopsPropagation;
168+
169+
#[StopsPropagation]
170+
final class MyEvent {}
171+
```
172+
173+
```php
174+
use Tempest\EventBus\StopsPropagation;
175+
use Tempest\EventBus\EventHandler;
176+
177+
final class MyHandler
178+
{
179+
#[StopsPropagation]
180+
public function handle(OtherEvent $event): void
181+
{
182+
// …
183+
}
184+
}
185+
```
186+
162187
## Built-in framework events
163188

164189
Tempest includes a few built-in events that are primarily used internally. While most applications won’t need them, you are free to listen to them if desired.

docs/2-features/17-oauth.md

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,21 @@ This implementation is built on top of the PHP league's [OAuth client](https://g
1212

1313
## Getting started
1414

15-
To get started with OAuth, you will first need to create a configuration file for your desired OAuth provider.
15+
Tempest provides an installer to quickly set up OAuth in your project. You can run the installer using the following command:
16+
17+
```sh
18+
./tempest install auth --oauth
19+
```
20+
21+
The installer will:
22+
- Prompt you to select one or more OAuth providers from the available options
23+
- Publish the necessary configuration files and controller stubs
24+
- Optionally add the OAuth credentials to your `.env` and `.env.example` files
25+
- Optionally install the required Composer dependencies for the selected providers
26+
27+
This is the quickest way to get started with OAuth in your Tempest application.
28+
29+
Alternatively, you can manually create a configuration file for your desired OAuth provider.
1630

1731
Tempest provides a [different configuration object for each provider](#available-providers). For instance, if you wish to authenticate users with GitHub, you may create a `github.config.php` file returning an instance of {b`Tempest\Auth\OAuth\Config\GitHubOAuthConfig`}:
1832

docs/4-internals/01-bootstrap.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ description: "Learn the steps involved in bootstrapping the framework."
77

88
Here's a short summary of what booting Tempest looks like.
99

10-
- The entry point is either `public/index.html` or `./tempest`.
10+
- The entry point is either `public/index.php` or `./tempest`.
1111
- Tempest boots using the {b`\Tempest\Core\FrameworkKernel`}.
1212
- Bootstrap classes are located in the [`Tempest\Core\Kernel`](https://github.com/tempestphp/tempest-framework/tree/main/packages/core/src/Kernel) namespace.
1313
- First, discovery is started through the {b`\Tempest\Core\LoadDiscoveryLocations`} and {b`\Tempest\Core\LoadDiscoveryClasses`} classes.

docs/4-internals/03-view-spec.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -473,7 +473,7 @@ This component provides a form element that will post by default and includes th
473473

474474
```html
475475
<?php
476-
use function \Tempest\uri;
476+
use function \Tempest\Router\uri;
477477
?>
478478

479479
<x-form :action="uri(StorePostController::class)">

0 commit comments

Comments
 (0)