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!

16
Login or Register to join the conversation
Tac-Tacelosky Avatar
Tac-Tacelosky Avatar Tac-Tacelosky | posted 2 days ago

This looks like an awesome tool. Starting at the end (the 'finish' folder in the source), I'd like to see the final site with data. But there are no layouts. I see there's a nglayouts:import console command, butt I don't the see layouts from this tutorial there. Is it possible to get those layouts, so I can see it running locally without having to manually create each layout? Or am I missing something during the setup.

Reply

Hey Tac,

Are you sure you're in the finish/ code? Are you sure you're looking at the course download code of this exact tutorial? I just downloaded the zip archive of the course project code and I can see "src/Layouts/" and "templates/nglayouts/" folders with files inside.

Please, double check you're in the correct folder.

Cheers!

Reply
Joris-Mak Avatar
Joris-Mak Avatar Joris-Mak | posted 7 months ago

Starting now, I'm excited to see what this does.

In our agency we do Symfony or Drupal... and in a lot of projects which we start as Symfony, we end up doing 'a little bit of CMS-alike functionality'. So I've been looking for some bundle or something to add something simple to an existing project.

Recently, Sulu was made Symfony 6.x compatible, so I jumped on it. And I'm very, very happy with the CMS part. The documentation is a bit sketchy, but that might be because I'm used to the Symfony pages :wink:.

But that Sulu Admin that is written as a single React app is a bit of a downer. It means we either need to ship with two admins, one for our normal admin stuff (using custom code, or Easy Admin, or whatever) and then one for the CMS part. Yes, it can be extended, but with quite some scaffolding and then you 'only' get a simple CRUD style, like a data table with an add/edit form. That often won't be enough in the real world, and that means writing custom React views to add something to the admin...while I prefer to keep it in twig / php, or at least use my Vue expertise... but to learn React just to extend an CMS admin...

Reply

Hey Joris!

Thanks for sharing your thoughts about Sulu, and yea... I got your point, it's a bummer to be forced to learn new technology just because a third-party library is not flexible enough.
I hope you like Netgens, and let us know what you think about it once you've finished with the tutorial ;)

Cheers!

Reply

Hi Ryan!
What about license agreement of code in example? Can I customize it for any reason of use?

Reply

Hey Tasatko,

I'm afraid I don't fully understand your question. Do you mean if you can use the code used in this tutorial in other places?

Reply

Hey Tasatko,

Sorry for my super late reply, the holidays got in the middle. Feel free to use our code samples :)

Cheers!

1 Reply
Ruslan Avatar

HI ,
I get small issue:
when I run :
composer require netgen/layouts-standard
I got this error:
Fatal error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 1310720 bytes) in /workspaces/netGen/vendor/twig/twig/src/NodeVisitor/SafeAnalysisNodeVisitor.php on line 71

php -i | grep memory_limit
memory_limit => 128M => 128M

Should I set more limit?

Reply
Victor Avatar Victor | SFCASTS | Ruslan | posted 8 months ago | HIGHLIGHTED

Hey Ruslan,

Yep, you should :) 128M is too little for CLI when you try to run composer require/update commands. Actually, there is a better way, check the official docs to know more options how to fix it: https://getcomposer.org/doc/articles/troubleshooting.md#memory-limit-errors

Cheers!

2 Reply
Ruslan Avatar

Hi Victor,
Thank for that advice, it's helpful.

BR.
Ruslan.

Reply

Hey Ruslan,

Great, thanks for confirming it helped :)

Cheers!

Reply
Richard Avatar

Hi, I'd like so much to go on in this course but i'm stuck with this error :
Unable to find file "@LiveComponentBundle/Resources/config/routing/live_component.xml". [...]
I first downloaded the source code of the course : 'start'.

I did adjust the .env file to fit MySQL for Mac OS (credentials : root:root, base:'layouts')
Followed scrupulously the readMe text and I updated the vendor folder with composer and installed yarn.
Then yarn watch and start the php server.

Last, whether I include "docker-compose up -d" or not, I get this error.
Unable to find file "@LiveComponentBundle/Resources/config/routing/live_component.xml"
Same thing with the 'finish' folder :-(
What did I missed ?

Thanks for attention, Richard.

Reply

Hey @Richard!

Ah, I know the issue! Since you did a composer update, also do a composer recipes:update symfony/ux-live-component. Your upgrade probably upgraded you to the latest LiveComponents package, and a config file moved around in that version (updating the recipe will update the path to that config file).

Cheers!

Reply
Richard Avatar
Richard Avatar Richard | weaverryan | posted 8 months ago | edited

I had to complete with a

composer recipes:install symfony/ux-live-component --force -v

but, anyway it's working now.
Bonne soirée.

1 Reply

Yes, you're right about those flags. I'm glad it's working now! I'm the one who made that change on live components, so it's my own fault 😜

1 Reply
Cat in space

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

What PHP libraries does this tutorial use?

// composer.json
{
    "require": {
        "php": ">=8.1.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
    }
}
userVoice