SymfonyCasts
banner
symfonycasts.com
SymfonyCasts
@symfonycasts.com
Injecting Unicorns and Rainbows back into learning PHP // The official way to learn Symfony: http://SymfonyCasts.com
Symfony Bundle Development #36:
Final chapter! Let's top things off with a Symfony Flex recipe that gives our bundle a clean, friction-free installation experience.
Symfony Flex Recipe
We left off with this gross user experience when installing our bundle in a Symfony application. Let's create a Symfony Flex recipe to improve this! The recipe will add the required "Translation" entity,...
symfonycasts.com
December 11, 2025 at 9:01 AM
Symfony Bundle Development #35:
Publish or perish... Let’s add our bundle to Packagist and tag a 1.0 release! 🚀
Publish to Packagist and Release
Our bundle is now hosted on GitHub and our continuous integration with GitHub Actions is green! To make it installable via Composer, we need to publish it on Packagist. You won't be able to follow along...
symfonycasts.com
December 9, 2025 at 9:01 AM
Symfony Bundle Development #34:
Time to go public! We’ll add a GitHub Actions workflow for tests, static analysis, and coding standards, then create a fresh GitHub repo for our bundle and watch our CI spring to life. 🤞
CI with GitHub Actions
At long last, it's time to share our bundle with the world! First though, we'll add the configuration needed for GitHub Actions to run our tests, static analysis, and verify our coding standards. In our...
symfonycasts.com
December 8, 2025 at 9:01 AM
Symfony Bundle Development #33:
We’ve got tests, but it’s time to add another superpower: PHPStan! Static analysis helps reveal sneaky issues your test suite might miss - let's dig in!
Static Analysis with PHPStan
While *tests* verify your code works as expected by running it, *static analysis* examines your code without executing it. This helps catch potential issues that tests might miss
symfonycasts.com
December 5, 2025 at 3:42 PM
Symfony Bundle Development #32:
With code and tests locked in, it's time to give our bundle a little polish 💅 — add metadata, clean up docs, tidy exports, and bring in consistent, automated code styling with PHP CS Fixer.
Metadata & PHP CS Fixer
Bundle coding is done, and tests are passing on all our supported Symfony versions. We're on the home stretch! ## License File Let's add a license file to our bundle
symfonycasts.com
December 4, 2025 at 9:01 AM
Symfony Bundle Development #31:
Bundles don't get to be picky about their dependencies. So, let's widen those constraints and take our test suite on a tour of Symfony versions - including the wild, un-housebroken dev builds.
Testing with Multiple Symfony Versions
It's time to nail down the PHP and package dependency versions our bundle supports. ## Adding PHP Version Requirement If we look at our bundle's "composer
symfonycasts.com
December 3, 2025 at 9:01 AM
Symfony Bundle Development #30:
Leveling up! 🚀 Let’s upgrade our bundle's integration test to use the object translator service - full entities, real database, the whole deal.
Doctrine Tests
Time to change this integration test stub into a proper test for our bundle. We're going to use a real database and real entities for this! Over in the terminal, install Zenstruck Foundry to help us manage...
symfonycasts.com
December 2, 2025 at 9:01 AM
We don’t do sales often. In fact...
🎉 This is our ONE sale of the entire year.
Get 40% OFF SymfonyCasts (yes, even if you’re already subscribed).
Go learn something awesome!
symfonycasts.com/blackfriday
Black Friday 2025 | SymfonyCasts
PHP and Symfony Tutorial Screencasts - with free videos, scripts, and code downloads!
symfonycasts.com
November 27, 2025 at 11:24 AM
Let's gooo #SymfonyCon Amsterdam! Come by our booth to grab some socks 🧦 and swag!
November 27, 2025 at 6:45 AM
We're so excited for #SymfonyCon tomorrow! 🚀
November 26, 2025 at 2:11 PM
We’ve got unit tests, which is fantastic - but nothing beats integration tests that spin up a real Symfony app and show our bundle hard at work. 👷🏽👷‍♀️
Integration Testing
We have our bundle's unit tests working - now for something a bit more complicated: integration tests. These tests will use the full Symfony service container, just like in a real application
symfonycasts.com
November 26, 2025 at 9:01 AM
Our bundle has been living at home, mooching off our parent app's dependencies. Time to cut the apron strings and set it up with its own - and make sure it can run its tests independently, too!
Bundle Dependencies
At the moment, our bundle is nested within a full-fledged Symfony application. It's relying on the dependencies of the application without defining any of its own
symfonycasts.com
November 25, 2025 at 9:01 AM
Step 2 in managing object translations in our bundle: an import command to load translated values - and we'll handle a bug fix along the way.
Translations Import Command
Before we tackle the import command, I noticed a bug in our "ObjectTranslator". Open that up and take a look at the "translate()" method
symfonycasts.com
November 19, 2025 at 9:01 AM
This bundle is nearly ready for a 1.0 release! The final feature: managing object translations. Step one: an export command to extract all translatable fields. Let's roll!
Export Translations Command
Alright, we're almost done the coding for a 1.0 release
symfonycasts.com
November 17, 2025 at 9:01 AM
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