Static Pages
Tempest comes with a built-in static site generator. 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 via your webserver.
final readonly class HomeController { #[StaticPage] #[Get('/')] public function home(): View { return view('home'); } }
Compiling all static pages is done with the static:generate
command:
./tempest static:generate
You can also remove all statically generated pages with the static:clean
command:
./tempest static:clean
Note that static:clean
will remove all HTML pages in your public folder, use this command with caution!
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 docs website:
final readonly class DocsController { #[StaticPage(DocsDataProvider::class)] #[Get('/{category}/{slug}')] public function show(string $category, string $slug, ChapterRepository $chapterRepository): View { return new DocsView( chapterRepository: $chapterRepository, currentChapter: $chapterRepository->find($category, $slug), ); } }
In this case, the #[StaticPage]
attribute gets a reference to the DocsDataProvider
, which implements the \Tempest\Http\DataProvider
interface:
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 the needs to be generated. In case of the docs controller, the action needs a $category
and $slug
, as well as a $chapterRepository
. That $chapterRepository
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 docs chapter. We can use the ChapterRepository
to get a list of all available chapters. Eventually, our data provider looks like this:
final readonly class DocsDataProvider implements DataProvider { public function __construct( private ChapterRepository $chapterRepository ) {} public function provide(): Generator { foreach ($this->chapterRepository->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 > /Users/brent/Dev/tempest-docs/public/framework/01-getting-started/index.html - /framework/02-the-container > /Users/brent/Dev/tempest-docs/public/framework/02-the-container/index.html - /framework/03-controllers > /Users/brent/Dev/tempest-docs/public/framework/03-controllers/index.html - /framework/04-views > /Users/brent/Dev/tempest-docs/public/framework/04-views/index.html - /framework/05-models > /Users/brent/Dev/tempest-docs/public/framework/05-models/index.html - /* … */
Deployments
All static pages are compiled to ./public/path-to-page/index.html
, most webservers will automatically serve these static pages for you without any additional setup.
Finally, keep in mind that static pages should be regenerated on every deploy. You should add the ./tempest static:generate
command in your deployment pipeline.