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.
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.
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)); } }
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()); } }
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.
<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>
<!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>
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.
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();
Configuration objects for easy autocompletion and injection, a data mapper, a powerful dependency container with autowiring. Tempest is designed to be frictionless.
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'), );
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); } }