Tempest features a unique concept called discovery. Tempest will scan your code and find out what to do with it: from controller routes to event handlers, from console commands to dependency initializers; Tempest will detect everything 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([self::class, 'show'], book: $book->id); } }
Tempest dares to reimagine templating in PHP with a clean and modern front-end engine, inspired by clean and modern front-end frameworks. Do you prefer something tried and tested? Tempest has support for Blade 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>
Define models with simple, clean code. Complete with built-in validation, relations, migrations, and more. 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\Modules\Books\Models\Chapter[] */ public array $chapters = [], ) {} }
I really like the way this framework turns out. It is THE framework in the PHP space out there for which I am most excited about as it allows me to make up the project structure myself. Only thing missing right now is async commands but it will come. So: Great job!
– GitHub
Just define your command, handle input dynamically, and deliver instant feedback. Tempest doesn't bother you with complex command definitions, just write your PHP code, and Tempest will figure out the rest. Interactive console components included!
final readonly class InteractiveCommand { use HasConsole; #[ConsoleCommand('hello:world')] public function __invoke(string $name, bool $continue = false): void { $this->writeln("Hello {$name}!"); if (! $continue && ! $this->confirm('Are you sure about this?')) { return; } $framework = $this->ask( question: 'What\'s your favourite framework?', options: [ 'Tempest', 'Laravel', 'Symfony', ], ); $this->success($framework); } }
Get static pages up and running right out of the box with zero hassle. Simply define your routes, and Tempest takes care of the rest — fetching the content and rendering it dynamically.
final readonly class DocsController { #[StaticPage(DocsDataProvider::class)] #[Get('/{category}/{slug}')] public function __invoke(string $category, string $slug): View { /* … */ } }
tempest static:generate - /docs/framework/01-getting-started > /home/forge/tempest.stitcher.io/public/docs/framework/01-getting-started.html - /docs/framework/02-the-container > /home/forge/tempest.stitcher.io/public/docs/framework/02-the-container.html - /docs/framework/03-controllers > /home/forge/tempest.stitcher.io/public/docs/framework/03-controllers.html - /* … */ Done
Tempest has already managed to become something more than an exercise, and you seem to have the experience, mentality and passion to lead its future to much greater heights.
– Reddit
Configuration objects instead of arrays for easy autocompletion and injection, caching, a powerful dependency container at its heart, autowiring everywhere, there's so much to show. Take a look!
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); } }