Integrate Symfony with Storyblok
Use Storyblok to manage the content of your website built with Symfony.
Create a new Symfony project by following the Installation page from its official documentation.
If you already have a Storyblok account, go to app.storyblok.com or log in with GitHub to continue.
Create a new blank space to follow the tutorial from scratch, or start from the core blueprint.
Installation
Section titled “Installation”In the terminal, cd
into your Symfony project and install the Storyblok packages.
composer require storyblok/php-content-api-client storyblok/symfony-bundle
In the root of your project, create a .env
file with the access token from your space.
###> storyblok/symfony-bundle ###STORYBLOK_API_BASE_URI=https://api.storyblok.comSTORYBLOK_API_TOKEN=your_storyblok_api_tokenSTORYBLOK_VERSION=draft # or published###< storyblok/symfony-bundle ###
Fetch a single story
Section titled “Fetch a single story”Create a Page
content type to fetch and render all stories of the page
content type.
<?php
declare(strict_types=1);
namespace App\ContentType;
use Storyblok\Bundle\ContentType\ContentType;
final readonly class Page extends ContentType{ public string $uuid; public string $name; public string $slug; public array $body; public \DateTimeImmutable $publishedAt;
public function __construct(array $values) { $this->uuid = $values['uuid']; $this->name = $values['name']; $this->slug = $values['full_slug']; $this->body = $values['content']['body'] ?? []; $this->publishedAt = new \DateTimeImmutable($values['published_at']); }
public function publishedAt(): \DateTimeImmutable { return $this->publishedAt; }}
Create a controller for your content type using the #[AsContentTypeController]
attribute.
<?php
declare(strict_types=1);
namespace App\Controller;
use App\ContentType\Page;use Storyblok\Bundle\ContentType\Attribute\AsContentTypeController;use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;use Symfony\Component\HttpFoundation\Request;use Symfony\Component\HttpFoundation\Response;
#[AsContentTypeController(contentType: Page::class)]final class PageController extends AbstractController{ public function __invoke(Request $request, Page $page): Response { return $this->render('page.html.twig', [ 'page' => $page, ]); }}
The #[AsContentTypeController]
attribute automatically registers the controller to handle requests for the specified content type.
Add the Twig templates used during rendering. Create a base layout at templates/base.html.twig
and a page template at templates/page.html.twig
.
<!DOCTYPE html><html> <head> <meta charset="UTF-8"> {% block stylesheets %} {% endblock %} {% block javascripts %} {% endblock %} </head> <body> <div class="container"> {% block body %}{% endblock %} </div> </body></html>
{% extends 'base.html.twig' %}
{% block body %} {% if page.body is defined and page.body is not empty %} {% for block in page.body %} {% if block is not null %} {{ block|render_block }} {% endif %} {% endfor %} {% endif %}{% endblock %}
The render_block
Twig filter automatically renders blocks using their registered templates.
Create blocks and templates
Section titled “Create blocks and templates”Stories might contain a body
or similar field which consists of an array with several blocks of custom types (e.g. Feature, Teaser, Grid) in it.
<?php
declare(strict_types=1);
namespace App\Block;
use Storyblok\Bundle\Block\Attribute\AsBlock;
#[AsBlock]final readonly class Feature{ public string $name;
public function __construct(array $values) { $this->name = $values['name'] ?? ''; }}
<?php
declare(strict_types=1);
namespace App\Block;
use Storyblok\Bundle\Block\Attribute\AsBlock;
#[AsBlock]final readonly class Teaser{ public string $headline;
public function __construct(array $values) { $this->headline = $values['headline'] ?? ''; }}
<?php
declare(strict_types=1);
namespace App\Block;
use Storyblok\Bundle\Block\Attribute\AsBlock;
#[AsBlock]final readonly class Grid{ public array $columns;
public function __construct(array $values) { $this->columns = $values['columns'] ?? []; }}
The #[AsBlock]
attribute automatically registers blocks for rendering. The template for each block will default to blocks/{name}.html.twig
.
The bundle will look for templates in the templates/blocks/
directory by default, create them as follow.
<div class="feature"> <span>{{ block.name }}</span></div>
<div class="teaser"> <h2>{{ block.headline }}</h2></div>
<div class="grid"> {% for column in block.columns %} <div> {{ column|render_block }} </div> {% endfor %}</div>
Similar to the Page template, the Grid
template iterates over the columns
block field and renders nested blocks.
Run your Symfony development server and go to the /home
route in your browser.
symfony server:start
Get in touch with the Storyblok community