Chapters
32 Chapters
|
4:16:27
|
Login to bookmark this video
-
Course Code
Subscribe to download the code!
Subscribe to download the code!
-
This Video
Subscribe to download the video!
Subscribe to download the video!
-
Subtitles
Subscribe to download the subtitles!
Subscribe to download the subtitles!
-
Course Script
Subscribe to download the script!
Subscribe to download the script!
Scroll down to the script below, click on any sentence (including terminal blocks) to jump to that spot in the video!
Subscribe to jump to this part in the video!
Keep on Learning!
If you liked what you've learned so far, dive in! Subscribe to get access to this tutorial plus video, code and script downloads.
What PHP libraries does this tutorial use?
// composer.json
{
"require": {
"php": ">=8.2",
"ext-ctype": "*",
"ext-iconv": "*",
"babdev/pagerfanta-bundle": "4.x-dev", // 4.x-dev
"doctrine/doctrine-bundle": "^2.10", // 2.12.x-dev
"doctrine/doctrine-migrations-bundle": "^3.2", // 3.4.x-dev
"doctrine/orm": "^2.16", // 2.18.x-dev
"knplabs/knp-time-bundle": "dev-main", // dev-main
"pagerfanta/doctrine-orm-adapter": "4.x-dev", // 4.x-dev
"pagerfanta/twig": "4.x-dev", // 4.x-dev
"symfony/asset": "6.4.*", // 6.4.x-dev
"symfony/asset-mapper": "6.4.*", // 6.4.x-dev
"symfony/console": "6.4.x-dev", // 6.4.x-dev
"symfony/dotenv": "6.4.x-dev", // 6.4.x-dev
"symfony/flex": "^2", // 2.x-dev
"symfony/form": "6.4.x-dev", // 6.4.x-dev
"symfony/framework-bundle": "6.4.x-dev", // 6.4.x-dev
"symfony/monolog-bundle": "^3.0", // dev-master
"symfony/runtime": "6.4.x-dev", // 6.4.x-dev
"symfony/security-csrf": "6.4.x-dev", // 6.4.x-dev
"symfony/stimulus-bundle": "2.x-dev", // 2.x-dev
"symfony/twig-bundle": "6.4.x-dev", // 6.4.x-dev
"symfony/ux-autocomplete": "2.x-dev", // 2.x-dev
"symfony/ux-live-component": "2.x-dev", // 2.x-dev
"symfony/ux-turbo": "2.x-dev", // 2.x-dev
"symfony/ux-twig-component": "2.x-dev", // 2.x-dev
"symfony/validator": "6.4.x-dev", // 6.4.x-dev
"symfony/web-link": "6.4.*", // 6.4.x-dev
"symfony/yaml": "6.4.x-dev", // 6.4.x-dev
"symfonycasts/dynamic-forms": "dev-main", // dev-main
"symfonycasts/tailwind-bundle": "dev-main", // dev-main
"tales-from-a-dev/flowbite-bundle": "dev-main", // dev-main
"twig/extra-bundle": "^2.12|^3.0", // 3.x-dev
"twig/twig": "^2.12|^3.0" // 3.x-dev
},
"require-dev": {
"doctrine/doctrine-fixtures-bundle": "^3.4", // 3.6.x-dev
"phpunit/phpunit": "^9.5", // 9.6.x-dev
"symfony/browser-kit": "6.4.*", // 6.4.x-dev
"symfony/css-selector": "6.4.*", // 6.4.x-dev
"symfony/debug-bundle": "6.4.x-dev", // 6.4.x-dev
"symfony/maker-bundle": "^1.51", // dev-main
"symfony/panther": "^2.1", // v2.1.1
"symfony/phpunit-bridge": "7.1.x-dev", // 7.1.x-dev
"symfony/stopwatch": "6.4.x-dev", // 6.4.x-dev
"symfony/web-profiler-bundle": "6.4.x-dev", // 6.4.x-dev
"zenstruck/browser": "1.x-dev", // 1.x-dev
"zenstruck/foundry": "^1.36" // 1.x-dev
}
}
What JavaScript libraries does this tutorial use?
// importmap.php
return [
'app' => [
'path' => './assets/app.js',
'entrypoint' => true,
],
'js-confetti' => [
'version' => '0.11.0',
],
'@hotwired/stimulus' => [
'version' => '3.2.2',
],
'@symfony/stimulus-bundle' => [
'path' => './vendor/symfony/stimulus-bundle/assets/dist/loader.js',
],
'tom-select' => [
'version' => '2.3.1',
],
'tom-select/dist/css/tom-select.default.css' => [
'version' => '2.3.1',
'type' => 'css',
],
'@hotwired/turbo' => [
'version' => '7.3.0',
],
'stimulus-popover' => [
'version' => '6.2.0',
],
'debounce' => [
'version' => '1.2.1',
],
'turbo-view-transitions' => [
'version' => '0.3.0',
],
'stimulus-use' => [
'version' => '0.52.1',
],
'flowbite' => [
'version' => '2.2.1',
],
'@popperjs/core' => [
'version' => '2.11.8',
],
'flowbite-datepicker' => [
'version' => '1.2.6',
],
];
20 Comments
Why in modern development we need a library for everything, even for transitioning the visibility from 100 to 0... 😅 it's mindblowing, how do we verify that all those libraries are trusted...
Hey @Francesco!
This is a fair observation. I think it's better than it was several years ago. Modern JS has many of the features we used to use libraries for.
As for trusting the packages. There is the
auditcommand to look for security vulnerabilities. I think your talking about supply chain attacks though. Indeed, this is a managed risk with every package manager, including composer.npm has the concept of signed packages you could look into. I believe there's been some discussion about this idea being added to composer too.
--Kevin
While time showing up the message is perfectly configurable (data-closeable-auto-close-value="2000") the time for the timebar is hardcoded.
`<div
What's you recommendation for solving that issue?
Hey @lid
An option would be to pass a Twig variable from the controller and generate the CSS class dynamically
{{ 'duration-['~time~'ms]' }}Cheers!
Thanks for your suggestion. Unfortunately, I would prefer a solution where configuration needs to be done at one position only. The notification is a component, a small one - at the client-side.
I managed to get it working this way:
In closeable_controller.js
Does something speak against it?
Thank you very much!
It requires a bit more JS code but if you plan to re-use that controller in many places I think it's a better approach than mine
Cheers!
Hi and thank you for this great tutorial.
I find that this "simple" approach to setting up flash messages is great, however, it seems to be limited in the case of different asset configurations. That is, if there is a "Backend" and a "Frontend" part, each with its own asset system, we have to put a data-turbo-track attribute for the page to completely reload.
So, if we emit a flash message from the backend for it to display on the frontend, there's a kind of double page refresh, and therefore the flash message is "lost" in between.
I don't know if there's a solution to manage this.
Hey @labfordev
Can you tell me why it would trigger a double-page refresh? I think that's more related to how your frontend and backend communicate with each other.
Actually, I'm using Vite.js to manage my assets, and it behaves and functions quite similarly to Webpack Encore. I have an asset configuration for the backend and an asset configuration for the frontend. Each with its own stimulus controllers, etc...
On the import of the JS entry file into my HTML, I added, for both the back and front parts, a data-turbo-track="reload" attribute so that the browser reloads the page when I switch from the backend to the frontend and vice versa.
When I launch a flash message from the backend, for example, or even more concretely from an event listener at the moment of user logout, it's impossible to display this flash message on the frontend (landing page following the logout).
It seems like turbo makes an ajax call to the frontend, and since it sees the data-turbo-track attribute, it reloads the page completely. Consequently, the flash message seems to have already been consumed in the meantime.
I'm not sure if this is very clear... Sorry for my very Frenchy English ^^
I think it closely resembles these issues:
Hey @labfordev!
Yes, I understand! Interesting - and that first issue, indeed, seems to be exactly what you're talking about! That's tricky. Honestly, I can't think of a great workaround :/. From our Symfony app, we have no idea that the first page request is about to be ignored and then a 2nd will follow... so we can't add any intelligence that would say "please don't remove the flash messages yet". The only ideas I have are:
A) Disable Turbo on forms submits where you might know this will happen. This, I admit, is not a super great solution.
B) In theory (?), you could check the
Referer. And if the current request is for the frontend, and theRefererwas for the backend, you could add some special code to "keep" the flashes in the container for an extra request. This... seems like it would work... but it also feels like there could be cases I'm not thinking about. To "keep" the flash messages for an extra request, you could... possibly create a custom Twig function -is_switching_areas()- that detects this situation. Then usepeekon the flashbag instead ofget().Sorry I can't be more helpful, but I am interested how you solve this :).
Cheers!
Hey @weaverryan!
Thank you for your great response! Indeed, it's quite a unique "problem" :p.
I'll try to look into it when I have a bit more time, following what you just said.
I'll get back to you if I find a solution.
Cheers!
Yea... those issues seem related to your problem. I don't know what's causing it. I'll see if Ryan can help us out
Thank you very much :)
Small typo in the script:
Should be autoClose?
Thanks for the mention @Rudi-T! All fixed now
Hi @weaverryan
can you please share, which Plugin(s) do you use for the autocomplete (on 1:04 by example) ?
Hey @Chris-56789 ,
Good question! That's a GitHub Copilot PhpStorm's plugin: https://github.com/features/copilot - a kind of AI autocompletion.
Cheers!
Thanks
Nice! I'd add a
data-turbo-temporaryattribute to the notification message itself so it's not added to the page cache if the user leaves the page before the notification is closed/removed (it would cause a weird behavior if they get back to the page again and the notification is in the page cache, they'd see it for a short moment as the live page version is being fetched and replaces the cached version). This means the notification will be removed from the document whenever the user goes to another page before the notification closes. To avoid losing the notification when a user leaves the page, you could make the notifications wrapper elementdata-turbo-permanentand give it an ID, but unfortunately, this has a weird side-effect of not adding new notifications to the wrapper element if you're doing that with regular flash+redirects (since the permanent elements won't be touched)... maybe that's also fixed with Turbo Streams?Hey @tonysm!
Absolutely! I do this too. I forgot to do it in the video, but added it later... and meant to add a note to this chapter, you just reminded me to add! :).
Hmm, interesting! Indeed, streams would fix this. I've never done it before, but instead of actually rendering the streams inside of the
<div id="flash-container">, you could render them right below/above this as a stream:This should work. It looks a bit odd - instead of physically rendering into
flash-container... you render an element that says "render this intoflash-container", but it should work. I'd love to know how it works in practice!Cheers!
"Houston: no signs of life"
Start the conversation!