Static pages
Overview
When a controller action is tagged with #[StaticPage]
, it can be compiled by Tempest as a static HTML page. These pages can then directly be served directly through your web server.
use Tempest\Router\Get; use Tempest\Router\StaticPage; use Tempest\View\View; use function Tempest\view; final readonly class FrontPageController { #[StaticPage] #[Get('/')] public function frontpage(): View { return view('./front-page'); } }
Compiling and cleaning up static pages is done using the static:generate
and static:clean
commands, respectively. Note that the latter removes all HTML files and empty directories in your /public
directory.
./tempest static:generate ./tempest static:clean
Data providers
Since most pages require some form of dynamic data, static pages can be assigned a data provider, which will generate multiple pages for one controller action.
Let's take a look at the controller action for this very website:
use Tempest\Router\Get; use Tempest\Router\StaticPage; use Tempest\View\View; final readonly class ChapterController { #[StaticPage(ChapterDataProvider::class)] #[Get('/{category}/{slug}')] public function show(string $category, string $slug, ChapterRepository $chapters): View { return new ChapterView( repository: $chapters, current: $chapters->find($category, $slug), ); } }
In this case, the #[StaticPage]
attribute gets a reference to the ChapterDataProvider
, which implements the Tempest\Router\DataProvider
interface:
use Tempest\Router\DataProvider; final readonly class DocsDataProvider implements DataProvider { public function provide(): Generator { // … } }
A data provider's goal is to generate multiple pages for one controller action. It does so by yielding an array of controller action parameters for every page that needs to be generated. In case of the documentation chapter controller, the action needs a $category
and $slug
, as well as the chapter repository.
That repository is injected by the container, so we don't need to worry about it here. What we do need to provide is a category and slug for each page we want to generate.
In other words: we want to generate a page for every documentation chapter. We can use the ChapterRepository
to get a list of all available chapters. Eventually, our data provider looks like this:
use Tempest\Router\DataProvider; final readonly class DocsDataProvider implements DataProvider { public function __construct( private ChapterRepository $chapters ) {} public function provide(): Generator { foreach ($this->chapters->all() as $chapter) { // Yield an array of parameters that should be passed to the controller action, yield [ 'category' => $chapter->category, 'slug' => $chapter->slug, ]; } } }
The only thing left to do is to generate the static pages:
./tempest static:generate /framework/01-getting-started ............. /public/framework/01-getting-started/index.html /framework/02-the-container ................. /public/framework/02-the-container/index.html /framework/03-controllers ..................... /public/framework/03-controllers/index.html /framework/04-views ................................. /public/framework/04-views/index.html /framework/05-models ............................... /public/framework/05-models/index.html // …
Production
Static pages are generated in the /public
directory, as index.html
files. Most web servers will automatically serve these static pages for you without any additional setup.
Note that static pages are meant to be generated as part of your deployment script. That means the ./tempest static:generate
command should be in your deployment pipeline.