Tempest is a PHP MVC framework that gets out of your way. Give it a ⭐️ on GitHub! Tempest's design philosophy is that developers should write as little framework-related code as possible, so that they can focus on application code instead.
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.
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 cd my-app
This 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
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
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
Installing Tempest into a project means copying one or more of these files into that project:
public/index.php
— the web application entry pointtempest
– the console application entry point.env.example
– a clean example of a .env
file.env
– the real environment file for your local installationYou can choose which files you want to install, and you can always rerun the install
command at a later point in time.
Tempest won't impose any fixed file structure on you: one of the core principles of Tempest is that it will scan your project code for you, and it will automatically discover any files it needs to. 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. This is what's called discovery, and it's one of Tempest's most powerful features.
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:
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:
final readonly class RssSyncCommand { public function __construct(private Console $console) {} #[ConsoleCommand('rss:sync')] public function __invoke(bool $force = false): void { /* … */ } }
We'll cover controllers and console commands in depth in future chapters.