The framework thatgets out of your way.

Tempest embraces modern PHP and covers a wide range of features, giving you all the tools you need to focus on your code.

Zero-config code discovery

Tempest scans your code and finds out what to do with it without you having to write a single line of configuration or bootstrap code.

src/Books/BookController.php
final readonly class BookController
{
    // …

    #[Post('/books')]
    public function store(CreateBookRequest $request): Response
    {
        $book = map($request)->to(Book::class)->save();

        return new Redirect(uri([self::class, 'show'], book: $book->id));
    }
}
src/StarCountViewProcessor.php
final class StarCountViewProcessor implements ViewProcessor
{
    public function __construct(
        private readonly GitHub $github,
    ) {}

    public function process(View $view): View
    {
        if (! $view instanceof WithStarCount) {
            return $view;
        }

        return $view->data(starCount: $this->github->getStarCount());
    }
}
A refreshing new template engine

Tempest reimagines templating in PHP with a clean front-end engine, inspired by modern front-end frameworks.

Do you prefer something tried and tested? Tempest has built-in support for Blade and Twig as well.

posts/show.view.php
<x-base :title="$this->seo->title">
	<ul>
		<li :foreach="$this->posts as $post">
			{{ $post->title }}

			<span :if="$this->showDate($post)">
				<x-tag>
					{{ $post->date }}
				</x-tag>
			</span>
		</li>
	</ul>
</x-base>
x-base.view.php
<!DOCTYPE html>
<html lang="en" class="h-dvh flex flex-col">
<head>
	<title :if="isset($title)">{{ $title }} — Bookish</title>
	<title :else>Bookish</title>
	<meta charset="UTF-8" />
	<meta name="viewport" content="width=device-width, initial-scale=1.0" />
	<x-vite-tags />
	<x-slot name="head" />
</head>
<body class="antialiased flex flex-col grow">
	<x-slot />
	<x-slot name="scripts" />
</body>
</html>
An ORM that embraces modern PHP

Define models with simple, clean code.

We don't try to reinvent database querying from scratch, so whenever you need a complex query, you can write SQL directly.

src/Books/Book.php
final class Book implements DatabaseModel
{
    use IsDatabaseModel;

    public function __construct(
        #[Length(min: 1, max: 120)]
        public string $title,

        public ?Author $author = null,

        /** @var \App\Books\Chapter[] */
        public array $chapters = [],
    ) {}
}
$books = Book::query()
    ->with('author.publisher')
    ->where('createdAt < :olderThan', olderThan: $olderThan)
    ->orderBy('createdAt DESC')
    ->limit(5)
    ->all();
And much, much more.

Configuration objects for easy autocompletion and injection, a data mapper, a powerful dependency container with autowiring. Tempest is designed to be frictionless.

src/config/database.config.php
use Tempest\Database\Config\PostgresConfig;
use function Tempest\env;

return new PostgresConfig(
    host: env('DB_HOST'),
    port: env('DB_PORT'),
    username: env('DB_USERNAME'),
    password: env('DB_PASSWORD'),
    database: env('DB_DATABASE'),
);
src/Support/MarkdownInitializer.php
final readonly class MarkdownInitializer implements Initializer
{
    public function initialize(Container $container): MarkdownConverter
    {
        $environment = new Environment();
        $highlighter = new Highlighter(new CssTheme());

        $highlighter
            ->addLanguage(new TempestViewLanguage())
            ->addLanguage(new TempestConsoleWebLanguage())
            ->addLanguage(new ExtendedJsonLanguage());

        $environment
            ->addExtension(new CommonMarkCoreExtension())
            ->addExtension(new FrontMatterExtension())
            ->addRenderer(FencedCode::class, new CodeBlockRenderer($highlighter))
            ->addRenderer(Code::class, new InlineCodeBlockRenderer($highlighter));

        return new MarkdownConverter($environment);
    }
}