Flag of Ukraine
SymfonyCasts stands united with the people of Ukraine

Hello Layouts+ Setup!

Video not working?

It looks like your browser may not support the H264 codec. If you're using Linux, try a different browser or try installing the gstreamer0.10-ffmpeg gstreamer0.10-plugins-good packages.

Thanks! This saves us from needing to use Flash or encode videos in multiple formats. And that let's us get back to making more videos :). But as always, please feel free to message us.

Hey friends! I'm so glad you're here with me, because this tutorial is about something fun, cool, and quite powerful. No, it's not about a masked, crime-fighting feline with superpowers, though that would be pretty cool. This tutorial is all about the Netgen Layouts package.

What Is Layouts?

This library has existed for years, but I've only recently checked it out. Layouts is, very simply, a way to take any existing Symfony app and add the ability to dynamically rearrange how your pages are organized on the fly via an admin section... including adding new dynamic content. It's a really cool mixture of a normal Symfony app with controllers and Twig templates... plus content management features that you can opt into on a page-by-page basis. I particularly love the opt-in approach

Who Needs Layouts?

Why would you go to the trouble of using Layouts in your Symfony app? Well, not all projects need this. But if an admin user needs to be able to make changes to how your site and its content are organized, then this is for you. This includes being able to add and change collections of items - like featured products - right to the middle of an existing page, rearranging content from a Twig template higher or lower on the page, adding some completely new customizable content to a page or creating temporary landing pages and allowing all of this to be done by regular ol' users. You can leverage Layouts for a single page on your site, leaving everything else to be a normal Symfony app, or every page on your site can use it. Like I said, you opt into Layouts as you see fit.

Project Setup

I could go on and on, but it's probably best to see the Layouts magic in action. It's super fun to play with, so you should definitely download the course code from this page and code along with me. When you unzip the file, you'll find a start/ directory with the same code that you see here. Pop open this README.md file for all those sweet setup details. I've already gone over to my terminal, installed my Node assets via:

yarn install

and ran:

yarn watch

to build my CSS and JS files. But that's all just to make our app and this tutorial more realistic. Layouts doesn't require us to use Encore and it doesn't mess with our CSS and JS at all.

Anyway, the last step in the README is to open another terminal tab and run:

symfony serve -d

to start a web server at https://127.0.0.1:8000 - I'll cheat and click that. And... hello new side project: it's Bark & Bake! Listen, dogs are pretty tired of our lazy attempts at canine cuisine. Crunchy kibble? No thanks. So we've built this site to inspire people to be the best chefs they can be... for their dogs.

This is a pretty traditional Symfony app with a few controllers and some Twig templates. It also has two entities: A User entity for security, and a Recipe entity. On the site, we have a homepage that shows the latest and greatest recipes, a recipe section, and the ability to open a specific recipe, so we can follow along in the kitchen. That's it. This skills stuff isn't implemented at all yet.

So, other than being able to edit the details of each recipe via an admin area, this is a static site! Time to change that! Soon, we'll be able to take this homepage - which is written via a normal Symfony controller and template... as you can see here - and use layouts to dynamically insert content and rearrange things!

Installing Layouts

So let's get Layouts installed. Find your terminal and run:

composer require netgen/layouts-standard

This will download several packages, including a couple of new bundles. When it finishes, run:

git status

to see that it also gave us two new route files, which add some admin routes that we're going to see in a few minutes.

Running the Migrations

Layouts also requires some extra database tables where it stores info about the layout's we'll create as well as any custom content we're putting into them. We'll see all of that in the Layouts admin section in a minute. To add the needed tables, scroll up and copy this nifty doctrine:migrations:migrate line.

This is kind of cool. The layouts packages comes with migrations... and this executes those. Paste this command, but if you're using the Docker database setup that we described in the README - I am - then modify this to start with symfony console so that it can inject the Docker environment variables that point to our database:

symfony console doctrine:migrations:migrate --configuration=vendor/netgen/layouts-core/migrations/doctrine.yml

And... perfect! One caveat is that these migrations are written for MySQL specifically. Layouts only supports MySQL right now.

Ignoring the Custom Tables

For the most part, Layouts is going to entirely manage all of the tables that we just added: we don't need to do anything with them. But now that those exist in our database, if we were to add a new entity and then generate a migration for that... the migration would try to drop all of the Netgen Layouts tables. Watch! Run:

symfony console doctrine:schema:update --dump-sql --complete

This mimics generating a migration, and... yup! It wants to drops all of the Layouts tables. To fix this, head into config/packages/doctrine.yaml and, under dbal, add schema_filter, and pass a regular expression... which you can copy from the Layouts documentation:

doctrine:
dbal:
... lines 3 - 7
schema_filter: ~^(?!nglayouts_)~
... lines 9 - 44

Perfect! With that, if we go back and run the doctrine:schema:update command again...

symfony console doctrine:schema:update --dump-sql --complete

It's clean, except for doctrine_migration_versions. But, no worries: the make:migration command is smart enough not to drop its own table.

Ok, Netgen Layouts is installed and it has the database tables it needs. If we go back and refresh our site now... congratulations! Absolutely nothing is different. Though, we do have a cute little web debug toolbar icon down here that we'll talk about later.

This, again, is one of the great things about Layouts. Just installing it does not take over your app. Layouts is not being used at all to render this page.

Next, let's dive into the Layouts admin area to create our first layout. Then, we'll see how that interacts with the real pages on our site.

Leave a comment!

0
Login or Register to join the conversation
Cat in space

"Houston: no signs of life"
Start the conversation!

What PHP libraries does this tutorial use?

// composer.json
{
    "require": {
        "php": ">=8.0.0",
        "ext-ctype": "*",
        "ext-iconv": "*",
        "babdev/pagerfanta-bundle": "^3.7", // v3.7.0
        "doctrine/doctrine-bundle": "^2.7", // 2.7.0
        "doctrine/doctrine-migrations-bundle": "^3.2", // 3.2.2
        "doctrine/orm": "^2.13", // 2.13.3
        "easycorp/easyadmin-bundle": "^4.4", // v4.4.1
        "netgen/layouts-contentful": "^1.3", // 1.3.2
        "netgen/layouts-standard": "^1.3", // 1.3.1
        "pagerfanta/doctrine-orm-adapter": "^3.6",
        "sensio/framework-extra-bundle": "^6.2", // v6.2.8
        "stof/doctrine-extensions-bundle": "^1.7", // v1.7.0
        "symfony/console": "5.4.*", // v5.4.14
        "symfony/dotenv": "5.4.*", // v5.4.5
        "symfony/flex": "^1.17|^2", // v2.2.3
        "symfony/framework-bundle": "5.4.*", // v5.4.14
        "symfony/monolog-bundle": "^3.0", // v3.8.0
        "symfony/proxy-manager-bridge": "5.4.*", // v5.4.6
        "symfony/runtime": "5.4.*", // v5.4.11
        "symfony/security-bundle": "5.4.*", // v5.4.11
        "symfony/twig-bundle": "5.4.*", // v5.4.8
        "symfony/ux-live-component": "^2.x-dev", // 2.x-dev
        "symfony/ux-twig-component": "^2.x-dev", // 2.x-dev
        "symfony/validator": "5.4.*", // v5.4.14
        "symfony/webpack-encore-bundle": "^1.15", // v1.16.0
        "symfony/yaml": "5.4.*", // v5.4.14
        "twig/extra-bundle": "^2.12|^3.0", // v3.4.0
        "twig/twig": "^2.12|^3.0" // v3.4.3
    },
    "require-dev": {
        "doctrine/doctrine-fixtures-bundle": "^3.4", // 3.4.2
        "symfony/debug-bundle": "5.4.*", // v5.4.11
        "symfony/maker-bundle": "^1.47", // v1.47.0
        "symfony/stopwatch": "5.4.*", // v5.4.13
        "symfony/web-profiler-bundle": "5.4.*", // v5.4.14
        "zenstruck/foundry": "^1.22" // v1.22.1
    }
}