SymfonyCasts
banner
symfonycasts.com
SymfonyCasts
@symfonycasts.com
Injecting Unicorns and Rainbows back into learning PHP // The official way to learn Symfony: http://SymfonyCasts.com
Like any other service your bundle provides, console commands need a little manual wiring. Let's roll up our sleeves, hook up our warmup command - and squash a few sneaky bugs while we’re at it!
Warmup Command Configuration
We have our warmup command class created, now we need to configure it as a service. In your apps, this would be done automatically because of the "AsCommand" attribute, but in bundles, like any other...
symfonycasts.com
November 11, 2025 at 9:01 AM
Bundles can totally have their own commands! Let’s create one to prepare the translation cache to keep apps snappy.
Cache Warmup Command
Alright, so by default, our object translations are cached indefinitely. We can configure an expiry, but what if we wanted to force an early refresh? Perhaps we've updated the database with new translations,...
symfonycasts.com
November 10, 2025 at 9:01 AM
Okay, our ObjectTranslator class is getting a bit complex - let's refactor the Doctrine logic into its own class. Phew, that's better!
Refactoring `ObjectTranslator`
Our "ObjectTranslator" is growing a bit large, and our "translationsFor" method has ballooned. To tackle this, we'll create a new service that will take care of all the Doctrine-related tasks
symfonycasts.com
November 4, 2025 at 9:01 AM
Add extra context to your PHP classes with zenstruck/class-metadata. This lightweight package lets you define short, readable identifiers for your classes - known as aliases - and attach custom metadata directly to them.
symfonycasts.com/blog/package...
Package Spotlight: `zenstruck/class-metadata`
Add extra context to your PHP classes with "zenstruck/class-metadata". This lightweight package lets you define short, readable identifiers for your classes - known as aliases - and attach custom…
symfonycasts.com
October 27, 2025 at 8:00 AM
It's alllliiivvveee 🧟! Our Caching is up and running! Let’s make it customizable with more bundle config - and see that cache tagging in action.
Cache Configuration
Our object translations are successfully being cached! I now want to allow the user to configure their cache pool and *how long* to cache the translations. Let's use our old friend, the bundle configuration...
symfonycasts.com
October 15, 2025 at 9:03 AM
Performance boost round 2: we'll Use Symfony’s Cache Contracts to cut DB queries - and check out cache tagging!
Performance Optimization 1: Caching
We have some in-memory memoization happening to reduce database calls, but, only for the duration of a single request. We're still seeing 4 queries on the French homepage
symfonycasts.com
October 10, 2025 at 9:02 AM
Time for a Performance boost! We can cut down database queries with memoization (love that word) and use PHP’s WeakMap to keep memory in check. 💥
Performance Optimization 1: Memoization
Our Twig filter is working as expected, and we're using it here in our article index. Right now, we're overriding the article variable with its translated version at the start of the loop
symfonycasts.com
October 9, 2025 at 9:03 AM
Our bundle could use a Twig filter. Let's add one and use a Twig runtime to keep things snappy! Oh, and shhh... we'll look at hidden services too. 🕵️‍♀️
`translate_object` Twig Filter
We have our "ObjectTranslator" service fully working. It can be injected and used in PHP code like we're doing in "ArticleController::show()"
symfonycasts.com
October 7, 2025 at 9:01 AM
Our translations work 🥳 but relying on the idea that all entities will have a getId() method? Kinda risky. Let’s make it rock-solid by letting Doctrine handle ID fetching - no hoping and wishing needed!
Fetch the Object ID with Doctrine
Currently, our French translation data is being successfully displayed on the page. However, our current method of fetching the ID using "$object->getId()" is a bit shaky
symfonycasts.com
October 6, 2025 at 9:01 AM
Our Setup is done! Now for the real fun, translating our objects 🎉 We’ll fetch + normalize translations with Doctrine and finally see content switch between English & French -- Oh là là!
Translation Logic
We've done a lot of setup work to get to this point, but it's time for the main event: translating our objects. Let's dive in! Our database has been loaded with these fixtures
symfonycasts.com
October 3, 2025 at 9:01 AM
We need to mark our Doctrine entities as "translatable". Sure, we could use an interface - but let’s be modern (and a little hip) by using PHP attributes instead!
Translatable Mapping
It's time to dive into how users will *mark* their app's entities for translation. For our app, we have four entities: "Article", "Category", "Tag", and "Translation"
symfonycasts.com
October 1, 2025 at 9:02 AM
We worked a bit with TDD previously, just getting a feel for it. Now it’s time to really lean in and use it in all its glory—rolling out a brand-new feature completely test-first!
TDD `TranslatedObject` Translations
The current logic of our "TranslatedObject" is solid. It effectively passes all method calls and property access to the underlying object
symfonycasts.com
September 30, 2025 at 9:01 AM
Let's roll up our sleeves, it's time to tackle our object wrapper Twig issue. We’ll replicate the problem in a unit test, then fix it - my favorite way to squash bugs!
TDD Getter Behaviour
We have our first test for "TranslatedObject", which is passing. When we wrote that test, we didn't *truly* use Test Driven Development, because the logic already existed - we just confirmed it with a...
symfonycasts.com
September 29, 2025 at 9:01 AM
Our bundle's object wrapper doesn’t play nicely with Twig. We'll fix that - but first, let’s write a unit test to be sure it works correctly outside of Twig. We'll all sleep better with code that's properly tested!
Unit Testing `TranslatedObject`
We have a little hiccup when using our "TranslatedObject" in Twig. Here's what's going on
symfonycasts.com
September 26, 2025 at 9:01 AM
Our bundle is all about translating objects. How are we going to do this? Well, let's look at some options and implement a solution! Booyah!
Translated Object Wrapper
Alright, so now we have a way to store our translations. Let's dive into how we can make use of them
symfonycasts.com
September 24, 2025 at 9:02 AM
Our bundle’s configuration is validated and ready to go, woohoo! Now, let’s put that config to work by injecting it into one of our bundle’s services so it can actually do something useful.
Using Bundle Configuration
In our bundle, we've defined and validated the "translation_class" configuration option. In our app, we've configured it as "App\Entity\Translation"
symfonycasts.com
September 22, 2025 at 9:01 AM
Bundle configuration nodes can have validation rules. These help make sure the user’s value is what you expect - no ‘cheeseburger’ when you wanted a number. Let’s look at some out of the box rules + create a custom rule!
Bundle Configuration Validation
Alight, we have this "translation_class" configuration option in our bundle. It needs some validation: first, it should be required, second, it should be a non-empty string, and third, it should be a...
symfonycasts.com
September 19, 2025 at 9:01 AM
Our bundle needs to know about our entity class. Sounds like the perfect job for bundle configuration! We'll define a "node" and add a description + example to help our future users! Go team!
Bundle Configuration
We need to let our bundle know about our shiny new "Translation" entity. Bundle configuration is the best way to do this
symfonycasts.com
September 18, 2025 at 9:02 AM
Our bundle has a Doctrine "mapped superclass" successfully registered. Now we need create the "real" entity in our app, let's go!
Extending our Bundle's Entity
Our bundle has an abstract "Translation" *mapped superclass* and is registered with Doctrine. Time to create the *real* "Translation" entity in our app
symfonycasts.com
September 17, 2025 at 9:01 AM
Our bundle now has an object to be used as a Doctrine entity ✅. Our next task is to provide mapping information and let Symfony + Doctrine know about it.
Configuring our Bundle's Entity
We created the abstract "Translation" class in our bundle. Now, we need to tell Doctrine about it so we can extend and use it in our app as a *real* entity
symfonycasts.com
September 16, 2025 at 9:01 AM
Bundles can totally provide Doctrine entities... but there are some tricks. Let's discuss the entity we need, create the class, see some bundle-specific considerations and have a great time along the way 😎
Entities in a Bundle
Our bundle needs a way to *store* the object translations. Since we're translating Doctrine entities from the database, we know a database is in use
symfonycasts.com
September 15, 2025 at 9:02 AM
In bundles, services need to be wired manually - just like Symfony apps in 2011! But don’t worry: it’s simpler now. While we can’t use autowiring inside the bundle, we can make our bundle’s services autowireable. Nice!
"Wiring Up" our Bundle Service
We created the class we want to use as a service in our bundle, but when we try to inject it, we get this "cannot autowire argument..." error. In your end apps, you might be used to this *just working*
symfonycasts.com
September 12, 2025 at 9:02 AM
Our bundle is kinda boring still. Let's spice it up with it's first service class!
Bundle Service Class
Ok, our bundle is installed and ready to roll. Time to add some functionality by adding our first service class
symfonycasts.com
September 11, 2025 at 9:01 AM
Even if you're developing bundles locally, you'll still need to install them with composer. Installation is a little different... but in a good way! We'll even stumble upon a hidden Symfony Flex feature 🌟
Install our Bundle Locally
We have a bundle "package" and bundle class, and even though it lives within our app, we still need to "install" it. This is handled with Composer like normal but the method is a little different
symfonycasts.com
September 10, 2025 at 9:01 AM
A bundle requires just one thing: a bundle class - the nerve center of your bundle. Let's create one, right after we fix a little quirk when working with multiple namespaces in the same project.
The Bundle Class
We have a home for our bundle within our app. And, we've set up it's "composer
symfonycasts.com
September 9, 2025 at 9:01 AM