Ludovic Frank - Freelance developer

Change theme colors dynamically with CSS and Symfony? It's possible

ionicons-v5-k Ludovic Frank Mar 25, 2024
98 reads Level: intermediate

Hello over here 🙂,

Thank you so much for clicking on this article 😁.

On the last post, I told you it smelled like spring, but now it's cooled off severely 😅.
Ah yes, it's true we're still not here to talk weather... I'm sorry (well, I think.).

This week, we're going to play with CSS and completely break Twig, you'll see it's fun, well, it's a bit "not very clean" as a method, but hey, on this blog, I tell you all about it.

Anyway, this week, we're making art (that's why the painting image for this article 😛).

But why do I need to do this?

Ah bah, always a "side project", remember the booking app with Symfony UX Turbo?

At the same time, I've spammed you so much with it that you shouldn't have forgotten it 😛.

This application was originally designed for a single restaurant, because let's face it, I couldn't see the value at the time. I did it because I was told it could solve a big problem...

And I'm forced to admit that, well, that's the case, this application, which was basically just another "side project", is running at full speed...

And what do you think happens when something goes well? Well, people keep asking me "how do I get it", and my answer to that is always:

You can't, it's not designed for large-scale deployment, it's designed for a single restaurant.

And that was true... until now.

The thing is, when your hairdresser (Hi Alex), your friends, your business contacts... tell you that this app is too good and that you should make it available to other restaurateurs... well, eventually, it gets into your head, so you get to work.

And that for each restaurant and its "reservation space", you need to be able to create totally different color themes for each establishment.

What CSS stack in the project?

For the time being, this project is Bootstrap for CSS (Is this the part where I get expensive? 😛), with the armor of utility classes, all "transpiled" from SASS to CSS.

What if we used different (SASS) themes for each restaurant?

This solution doesn't work for me, because it would mean that each time I redeploy, the CSS would be "transpiled" and would have to create as many CSS files as there are restaurants. This isn't viable, even if it's possible for a few restaurants, I don't know how many restaurants will use this application, and above all, you need to be able to change a color with one click 😁.

CSS, Twig, a controller and an entity

And here's how we're going to do it, we could put CSS directly in the HTML, but I don't like that idea, in fact, we're not exploiting the browser's cache by doing that, so we're going to do it a little cleaner.

The Twig

PHPStorm didn't understand what I was doing, because with Twig we use "{{ }}" to display variables, the problem is that in CSS we also use "{ }", so PHPStorm didn't really know what to do and this led to some funny situations.

Without further ado, here's the Twig code head:

Interesting, even Gitlab' s Twig interpreter doesn't really like this code 😅.

Why did you define the variables at the beginning of the file?
To be quite frank, it was quite an unpleasant job, I had to go and look in Bootstrap's classes or which class defined which color? And so, to make it easier to visualize my progress, I defined the variables at the beginning of the file.

Here, you can see the final file, but during the dev, I defined the colors directly in the file to immediately detect if there were any colors left over from the base test. Incidentally, for your viewing pleasure, here's the magnificent theme I designated during the creation of this css.twig file (I never thought I'd say that one day).

Beautiful, isn't it? It's absolutely horrible, we agree... but at least here I can see right away if there's any residue of the original CSS in the colors.

By the way, on this screenshot, you can see that I hadn't yet worked on Bootstrap's "alerts".

It should be noted here that I'm using the Twig "raw" filter, which is dangerous, as there's no filter and so CSS could be injected into my Twig file. To avoid this, I'll make a filter later 🙂 before the release.

Also, you can see that I'm using "custom" Twig filters in this code, it's simply a code retrieved from "StackOverflow" (real people know), which recalculates the gradient automatically:

There are some things wrong with this file, notably the function names, but I'll fix that later.

The controller

For our browser, this file has to be a CSS file and, above all, a file thatcan be "cached" by the browser.Otherwise, every time a user returns to the reservation process of his favorite establishment, he'll have to reload this file, and that's not in my values, I get bristly just at the thought of not exploiting the browser's cache. 🤣

So here's our controller:

The interesting part here is the response, in fact, we're going to tell Symfony that this is a CSS file, and that it must return in the "headers" that this file is public (therefore "cacheable" by CDNs), and that the browser can keep it cached.

If you pay close attention, you'll realize that caching is all very well, but if the theme changes, it won't change in the browsers of users who have already been there (or those who go through the same CDN server).
Don't worry, we'll see about that later.

As you can see in the code, we send to our ".css.twig", the "theme" variable which is "$restaurant->getTheme();" and this "getTheme()", returns a Doctrine entity.

The entity

Last but not least, the entity is what will store our theme in the database, but not only that...

The problem with the cache is that it has to be refreshed when the theme changes, and for this we've used a version of the file simply to change the URL of the file when we modify the theme.

Here's my entity:

Here you'll find all the theme colors and "$version", which will be a simple "int" that we'll update when we change the theme.

There are default values for each color, so you can have a "turnkey" theme that can be modified as soon as you create the basic restaurant. For the curious, here's the basic theme:

A little dark blue background and gold buttons, how's that for a theme?

Loading our CSS

To do this, nothing could be simpler, although the entity containing the theme must be accessible from your basic "Layout" (or if you wish, you can create a "block" and extend it to your Twig girl view.
In my case, the project being a bit special (remember, it was the first to use Symfony UX Turbo), I have access to the restaurant from the "base_customer.html.twig".

Don't forget to include your version in your URL - in my case, the "v" takes the value restaurant.theme.version.
This version number will be updated each time the modification form is saved.

The theme edit form

So, to be frank, I haven't written it yet, because it's going to come down to one command: "php bin/console make:form".
Then all you have to do is integrate it into the "back office" for restaurants and you're done.

Incidentally, if you'd like to see another CRUD I've done in the "back office", here the ability to add messages to the home screen:

Yes, it's nothing to do with that, but I had to show you something anyway 😁.

Conclusion

Here we are at the end of this article, I hope you enjoyed it and that it will be useful in your own projects.
See you soon in another article 🙂 even if I don't know yet what we'll talk about (and as I'm writing this, I just had an idea...).

Have a great week 🙂.