Flag of Ukraine
SymfonyCasts stands united with the people of Ukraine

Profiler: Your Debugging Best Friend

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.

Time to install our second package. And this one is fun. Let's commit our changes first: it'll makes it easier to check out any changes that the new package's recipe makes.

Add everything:

git add .

That looks fine so... commit:

git commit -m "Added some Tiwggy goodness"

Beautiful.

The debug Pack

Now run:

composer require debug

So yes, this is another Flex alias... and apparently it's an alias for symfony/debug-pack. And we know that a pack is a collection of packages. So instead of adding this one line to our composer.json file, if we check, it looks like it added one new package up under the require section - this is a logging library - and... all the way at the bottom, it added a new require-dev section with three other libraries.

The difference between require and require-dev isn't too important: all of these packages were downloaded into our app, But as a best practice, if you install a library that's only meant for local development, you should put it into require-dev. The pack did that for us! Thanks pack!

Recipe Changes

Back at the terminal, this also installed three recipes! Ooh. Let's see what those did. I'll clear the screen and run:

git status

So this is familiar: it modified config/bundles.php to activate three new bundles. Again, bundles are Symfony plugins, which add more features to our app.

It also added several configuration files to the config/packages/ directory. We will talk more about these files in the next tutorial, but, on a high level, they control the behavior of those bundles.

The Web Debug Toolbar And Profiler

So what did these new bundles give us? To find out, head over to your browser and refresh the homepage. Holy cats, Batman! It's the web debug toolbar. This is debugging madness: a toolbar full of good info. On the left, you can see the controller that was called along with the HTTP status code. There's also the amount of time the page took, the memory it used and also how many templates were rendered through Twig: this is the cute Twig icon.

On the right side, we have details about the Symfony local web server that's running and PHP info.

But you haven't seen the best part: click any of these icons to jump into the profiler. This is the web debug toolbar... gone crazy. It's full of data about that request, like the request and response, all of the log messages that happened during that request, information about the routes and the route that was matched, Twig shows you which templates were rendered and how many times they were rendered... and there's configuration information down here. Phew!

But my most favorite section is Performance. This shows a timeline of everything that happened during the request. This is great for two reasons. The first is pretty obvious: you can use this to find which parts of your page are slow. So, for example, our controller took 20.4 millisecond. And within the controller's execution, the homepage template rendered in 3.9 milliseconds and base.html.twig rendered in 2.8 milliseconds.

The second reason this is really cool is that it uncovers all the hidden layers of Symfony. Set this threshold down to zero. Previously, this only displayed things that took more than one millisecond. Now it's showing everything. You don't need to worry about the vast majority of the stuff, but it's super cool to see the layers of Symfony: the things that happen before and after your controller is executed. We have a deep dive tutorial for Symfony if you want to learn more about this stuff.

The web debug toolbar and profiler will also grow with our app. In a future tutorial, when we install a library to talk to the database, we will suddenly have a new section that lists all of the database queries that a page made and how long each took.

dump() and dd() Functions

Ok, so the debug pack installed the web debug toolbar. It also installed a logging library that we'll use later. And it installed a package that gives us two fantastic debug functions.

Head over to VinylController. Pretend that we're doing some developing and we need to see what this $tracks variable looks like. It's pretty obvious in this case, but sometimes you'll want to see what's inside a complex object.

To do that, say dd($tracks) where "dd" stands for dump and die.

... lines 1 - 9
class VinylController extends AbstractController
{
#[Route('/')]
public function homepage(): Response
{
... lines 15 - 22
dd($tracks);
... lines 24 - 28
}
... lines 30 - 43
}

So if we refresh... yup! That dumps the variable and kills the page. And this is a lot more powerful - and prettier - than using var_dump(): we can expand sections and see deep data really easily.

Instead of dd(), you can also use dump().. to dump and live. But this might not show up where you expect it to. Instead of printing in the middle of the page, it shows up down in the web debug toolbar, under the target icon.

... lines 1 - 9
class VinylController extends AbstractController
{
#[Route('/')]
public function homepage(): Response
{
... lines 15 - 22
dump($tracks);
... lines 24 - 28
}
... lines 30 - 43
}

If that's a bit too small, click to see a bigger version in the profiler.

Dumping in Twig

You can also use this dump() in Twig. Remove the dump from the controller... and then in the template, right before the ul, dump(tracks).

... lines 1 - 9
<div>
Tracks:
{{ dump(tracks) }}
... lines 14 - 20
</div>
... lines 22 - 23

And this... looks exactly the same. Except that when you dump in Twig, it does dump right into the middle of the page

And even more useful, in Twig only, you can use dump() with no arguments.

... lines 1 - 9
<div>
Tracks:
{{ dump() }}
... lines 14 - 20
</div>
... lines 22 - 23

This will dump all variables that we have access to. So here's the title variable, tracks and, surprise! There's a third variable called app. This is a global variable that we have in all templates... and it gives us access to things like the session and user data. And... we just discovered it by being curious!

So now that we've got these awesome debugging tools, let's turn to our next job... which is to make this site less ugly. Time to add CSS and a proper layout to bring our site to life!

Leave a comment!

14
Login or Register to join the conversation
Default user avatar
Default user avatar webcommenterdude | posted 1 year ago

A lot of time wasting on packs and recipes. Get to the point.

1 Reply

Hey Webcommenterdude,

Sorry if this video was boring for you because of long explaining of the installation process. Unfortunately, that is something we have to cover so other users do not get lost in it. Though, even in this short video we covered some new installed features like Symfony Web Debug Toolbar and VarDumper component. I bet the further chapters would be more interesting for you ;)

P.S. Keep in mind that this is the intro course into the Symfony 6 and is mostly designed for beginners. Yeah, if you already know Symfony and works with it - I agree, it might be less interesting for you... but you can rewind some known for you parts :)

Anyway, thank you for your feedback! We will definitely consider this in our future tutorials and try to spend less time on explaining simple things like the packs and recipes. We just wanted to cover it well now, and do not focus too much attention on it further in this course... and in further courses as well.

Cheers!

Reply

Thanks for the tutorial, I like that you explain recipes and composre in greater detail than in the tutorial for Symfony 5, where it was more like magic when the debug tool was installed. (It still is magical though 🪄)

Reply

Hey @Brentspine

Thanks for your feedback, and yes, recipes feel like magic, but it is good magic, they save so much time adding configuration

Cheers!

1 Reply
Krystian-S Avatar
Krystian-S Avatar Krystian-S | posted 1 month ago

Hi, I have problem. When i try install debug by "composer require debug" i receive:

In FileLoader.php line 172:

Container extension "debug" is not registered in C:\Users\surow\Symfony Projects\mixed_vinyl\config/packages/debug.yaml (which is being imported fr
om "C:\Users\surow\Symfony Projects\mixed_vinyl\src\Kernel.php").

In ContainerBuilder.php line 214:

Container extension "debug" is not registered.

Please, help.

Reply

Hey @Krystian-S

Do you already have a config/packages/debug.yaml file but the library it's not installed yet? Try removing the config file, and clear the cache manually just in case rm -r var/cache

Cheers!

Reply
Benanamen Avatar
Benanamen Avatar Benanamen | posted 5 months ago

One issue I had was the debug bar kept trying to load and would not. A .htaccess is required in the public directory for it to work.

` <IfModule mod_rewrite.c>

   RewriteEngine On
   RewriteCond %{REQUEST_FILENAME} !-f
   RewriteRule ^(.*)$ index.php [QSA,L]

</IfModule>`

Reply

Hey Benanamen,

Thank you for sharing it. If you install the library symfony/apache-pack it will generate the .htaccess for you. You can read more about how to configure a web server for a Symfony app https://symfony.com/doc/current/setup/web_server_configuration.html

Cheers

Reply
therouv Avatar

Followed the steps exactly and yet the toolbar does not appear on any of my browsers.
I've restarted the server, reinstalled the debug-bundle, made sure web_profiler.toolbar is set to true and that APP_ENV=dev... and still nothing.

What is wrong?

The /_profiler/ path works on the browser, but the toolbar is not appearing anywhere.

Reply

Hey Therouv,

Hm, did you make sure that the recipe for that package was executed? Sometimes you should allow executing it manually, but sometimes you. may allow it in your composer.json file. Though it might be forbidden in your composer.json and so no recipe was installed. Though, /_profile/ path works for you - I'd guess that the recipe was installed, but would be good to double check anyway. You can remove and install. the package again and look closer to the composer's output - it should have some recipe executed there.

Also, the very important requirement for the WDT to appear is that you should have <body> tag rendered on the page where you want to see it. Please, make sure you have a valid HTML markup on that page, especially the base html/head/body tags and that there are no any misprints or missing closing tags or brackets or quotes. I bet the invalid HTML syntax on that page prevents that WDT to show for you.

Also, try to clear the cache, i'd recommend you to remove the cache dir manually with rm -rf just in case. Sometimes it might be just. a simple cache problem.

I hope this helps!

Cheers!

1 Reply
therouv Avatar
therouv Avatar therouv | Victor | posted 9 months ago | HIGHLIGHTED

Also, the very important requirement for the WDT to appear is that you should have <body> tag rendered on the page where you want to see it. Please, make sure you have a valid HTML markup on that page, especially the base html/head/body tags and that there are no any misprints or missing closing tags or brackets or quotes. I bet the invalid HTML syntax on that page prevents that WDT to show for you.

That was it! I forgot to extend the block from base.html.twig. It works now.
Thank you!

1 Reply

Hey Therouv,

Ah, yeah, I got this problem as well before ;) Glad to hear we found the problem :) And thanks for confirming the root of the problem!

Cheers!

Reply
Default user avatar
Default user avatar unknown | posted 9 months ago | edited
Comment was deleted.

Hey Yuuki,

you mean on the commit message, right? That was made on purpose :)

Cheers!

Reply
Cat in space

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

What PHP libraries does this tutorial use?

// composer.json
{
    "require": {
        "php": ">=8.0.2",
        "ext-ctype": "*",
        "ext-iconv": "*",
        "symfony/asset": "6.0.*", // v6.0.3
        "symfony/console": "6.0.*", // v6.0.3
        "symfony/dotenv": "6.0.*", // v6.0.3
        "symfony/flex": "^2", // v2.1.5
        "symfony/framework-bundle": "6.0.*", // v6.0.4
        "symfony/monolog-bundle": "^3.0", // v3.7.1
        "symfony/runtime": "6.0.*", // v6.0.3
        "symfony/twig-bundle": "6.0.*", // v6.0.3
        "symfony/ux-turbo": "^2.0", // v2.0.1
        "symfony/webpack-encore-bundle": "^1.13", // v1.13.2
        "symfony/yaml": "6.0.*", // v6.0.3
        "twig/extra-bundle": "^2.12|^3.0", // v3.3.8
        "twig/twig": "^2.12|^3.0" // v3.3.8
    },
    "require-dev": {
        "symfony/debug-bundle": "6.0.*", // v6.0.3
        "symfony/stopwatch": "6.0.*", // v6.0.3
        "symfony/web-profiler-bundle": "6.0.*" // v6.0.3
    }
}
userVoice