Getting Started
Tempest is a PHP framework that gets out of your way. Its design philosophy is that developers should write as little framework-related code as possible, so that they can focus on application code instead.
Tempest embraces modern PHP syntax, covers a wide range of features: routing, MVC, ORM and database, rich console applications, events and commands, logging, a modern view engine, and unique capabilities such as discovery to improve developer experience.
Tempest can be installed as a standalone PHP project, as well as a package within existing projects. The framework modules — like, for example, tempest/console
or tempest/event-bus
— can also be installed individually, including in projects built on other frameworks.
Since code says more than words, here's a Tempest controller:
// app/BookController.php use Tempest\Http\Get; use Tempest\Http\Post; use Tempest\Http\Response; use Tempest\Http\Responses\Ok; use Tempest\Http\Responses\Redirect; final readonly class BookController { #[Get('/books/{book}')] public function show(Book $book): Response { return new Ok($book); } #[Post('/books')] public function store(CreateBookRequest $request): Response { $book = map($request)->to(Book::class)->save(); return new Redirect([self::class, 'show'], book: $book->id); } // … }
And here's a Tempest console command:
// app/MigrateUpCommand.php use Tempest\Console\Console; use Tempest\Console\ConsoleCommand; use Tempest\Console\Middleware\ForceMiddleware; use Tempest\Console\Middleware\CautionMiddleware; use Tempest\EventBus\EventHandler; final readonly class MigrateUpCommand { public function __construct( private Console $console, private MigrationManager $migrationManager, ) {} #[ConsoleCommand( name: 'migrate:up', description: 'Run all new migrations', middleware: [ForceMiddleware::class, CautionMiddleware::class], )] public function __invoke(): void { $this->migrationManager->up(); $this->console->success("Everything migrated"); } #[EventHandler] public function onMigrationMigrated(MigrationMigrated $migrationMigrated): void { $this->console->writeln("- {$migrationMigrated->name}"); } }
Ready to give it a try? Keep on reading, give Tempest a star️ on GitHub. If you want to be part of the community, you can join our Discord server, and you can check out our contributing guide!
Installation
You can install Tempest in two ways: as a web app with a basic frontend bootstrap, or by requiring the framework as a package in any project you'd like — these can be projects built on top of other frameworks.
A standalone Tempest app
If you want to start a new Tempest project, you can use tempest/app
as the starting point. Use composer create-project
to start:
composer create-project tempest/app my-app --stability alpha cd my-app
The project scaffold includes a basic frontend setup including tailwind:
npm run dev
You can access your app by using PHP's built-in server.
./tempest serve PHP 8.3.3 Development Server (http://localhost:8000) started
Tempest as a package
If you don't need an app scaffold, you can opt to install tempest/framework
as a standalone package. You could do this in any project; it could already contain code, or it could be an empty project.
composer require tempest/framework:1.0-alpha.3
Installing Tempest this way will give you access to the tempest console as a composer binary:
./vendor/bin/tempest
Optionally, you can choose to install Tempest's entry points in your project:
./vendor/bin/tempest install framework
Installing Tempest into a project means copying one or more of these files into that project:
-
public/index.php
— the web application entry point -
tempest
– the console application entry point -
.env.example
– a clean example of a.env
file -
.env
– the real environment file for your local installation
You can choose which files you want to install, and you can always rerun the install
command at a later point in time.
Project structure
Tempest won't impose any file structure on you: one of its core features is that it will scan all project and package code for you, and it will automatically discover any files the framework needs to know about. For example: Tempest is able to differentiate between a controller method and a console command by looking at the code, instead of relying on naming conventions or verbose configuration files. This concept is called discovery, and it's one of Tempest's most powerful features.
For example, you can make a project that looks like this:
app ├── Console │ └── RssSyncCommand.php ├── Controllers │ ├── BlogPostController.php │ └── HomeController.php └── Views ├── blog.view.php └── home.view.php
Or a project that looks like this:
app ├── Blog │ ├── BlogPostController.php │ ├── RssSyncCommand.php │ └── blog.view.php └── Home ├── HomeController.php └── home.view.php
From Tempest's perspective, it's all the same.
Discovery works by scanning you project code, and looking at each file and method individually to determine what that code does. For production apps, Tempest will cache the discovery process, so there's no performance overhead that comes with it.
As an example, Tempest is able to determine which methods are controller methods based on their route attributes:
// app/BlogPostController.php use Tempest\Http\Get; use Tempest\Http\Response; use Tempest\View\View; final readonly class BlogPostController { #[Get('/blog')] public function index(): View { /* … */ } #[Get('/blog/{post}')] public function show(Post $post): Response { /* … */ } }
And likewise, it's able to detect console commands based on their console command attribute:
// src/RssSyncCommand.php use Tempest\Console\HasConsole; use Tempest\Console\ConsoleCommand; final readonly class RssSyncCommand { use HasConsole; #[ConsoleCommand('rss:sync')] public function __invoke(bool $force = false): void { /* … */ } }
If you want to, you can read the internal documentation about discovery to learn more.
One important note to make is that you can disable all discovery cache for local development by added the follow environment variable:
# .env DISCOVERY_CACHE=false
Furthermore, you can always clear discovery caches via the terminal:
./tempest discovery:clear Tempest\Core\DiscoveryDiscovery cleared successful Tempest\Http\RouteDiscovery cleared successful Tempest\Http\Static\StaticPageDiscovery cleared successful Tempest\View\ViewComponentDiscovery cleared successful Tempest\Mapper\MapperDiscovery cleared successful Tempest\Console\Discovery\ScheduleDiscovery cleared successful Tempest\Console\Discovery\ConsoleCommandDiscovery cleared successful Tempest\Database\MigrationDiscovery cleared successful Tempest\EventBus\EventBusDiscovery cleared successful Tempest\Container\InitializerDiscovery cleared successful Tempest\CommandBus\CommandBusDiscovery cleared successful Done