Controlling the prod Environment
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.
With a Subscription, click any sentence in the script to jump to that part of the video!
Login SubscribeLet's see what our app looks like if we change to the prod environment. To do that, open the .env file and change APP_ENV to prod:
| // ... lines 1 - 15 | |
| ###> symfony/framework-bundle ### | |
| APP_ENV=prod | |
| // ... lines 18 - 22 |
Clearing Cache in the prod Environment
Cool! Now, find your browser, refresh and... it works! Well, actually, we got lucky. Behind the scenes, when we load a page, Symfony caches configuration, templates and other things for performance. In the dev environment, if we update a config file, Symfony automatically rebuilds the cache. So it's not something we even need to think about.
But in the prod environment - which is primed for performance - Symfony does not automatically rebuild your cache files. For example, if we added a new route to our app and then went to that URL in the prod environment, it would give us a page not found error! Why? Because our app would be using outdated routing cache.
That's why, whenever you change to the prod environment, you need to find your terminal and run a special command:
php bin/console cache:clear
This clears the cache so that, on our next reload, new cache will be built. The cache is stored in a var/cache/prod directory. Oh, and notice that bin/console is smart enough to know that we're in the prod environment.
In practice, I rarely switch to the prod environment on my local computer. The most common time I run cache:clear is when I'm deploying.
Now our app definitely works. And notice: no web debug toolbar!
Let's see Symfony's automatic caching system in action. Open up templates/question/show.html.twig and... let's make some small change - like Question::
| // ... lines 1 - 4 | |
| {% block body %} | |
| <div class="container"> | |
| <div class="row"> | |
| <div class="col-12"> | |
| <h2 class="my-4">Question:</h2> | |
| // ... lines 10 - 26 | |
| </div> | |
| </div> | |
| // ... lines 29 - 56 | |
| </div> | |
| {% endblock %} |
This time, when we refresh, the change is not there. That's because Symfony caches Twig templates. Now find your terminal, run:
php bin/console cache:clear
And come back to refresh. There's the change!
Different Cache Adapter in prod
Now that we understand environments, I have a challenge for us! At the top of the page, we're still dumping the cache service inside our controller. The class is ApcuAdapter because that's what we configured inside of config/packages/cache.yaml:
| framework: | |
| cache: | |
| // ... lines 3 - 13 | |
| # APCu (not recommended with heavy random-write workloads as memory fragmentation can cause perf issues) | |
| app: cache.adapter.apcu | |
| // ... lines 16 - 20 |
APCu is great. But maybe for simplicity, because it requires you to have a PHP extension installed, we want to use the filesystem adapter in the dev environment and APCu only for prod. How could we do that?
Let's think about it: we know how to override configuration in a specific environment... so we could override just this one config key in the dev environment.
To do that, in the dev/ directory, create a new file. It technically doesn't matter what it's called, but because we value our sanity, call it cache.yaml. Inside, say framework:, cache:, app: and the name of the original default value for this: cache.adapter.filesystem:
| framework: | |
| cache: | |
| app: cache.adapter.filesystem |
That's... all we need! Let's see if it works! Because we're still in the prod environment, find your terminal and clear the cache:
php bin/console cache:clear
When it finishes, go refresh the page. Good: in prod it's still using ApcuAdapter. Now go find the .env file at the root of the project... change APP_ENV back to dev:
| // ... lines 1 - 15 | |
| ###> symfony/framework-bundle ### | |
| APP_ENV=dev | |
| // ... lines 18 - 20 | |
| ###< symfony/framework-bundle ### |
And refresh the page.
Because the web debug toolbar is back, our dump is hiding inside its target icon. Let's see... yes! It's FilesystemAdapter!
Ok team: we've mastered environments and configuring services that are coming from bundles. So let's take things up to the next level: let's create our own service objects! That's next.
23 Comments
Funny, when I changed to the "dev" environment, the class remained "apcu", even though I've hit the reload. I had to clear the cache in the "dev" environment to see the change. I seems not everything in the cache is rebuilt in symfony's development server.
Hey Joao,
It should be rebuilt, but sometimes, especially when you use some virtualization tools like Docker, Vagrant, etc. it may not see the changes. But yeah, in any weird case the first thing to do after page refresh would be clearing the cache :)
I'm glad that cache:clear helped! And thanks for sharing it with others.
Cheers!
Hi, hope this isn't off topic. In my prod environment I wonder if my htaccess is setup correctly... because the "public" is normally not visible, but if I type in "mysite.com/public/" that works just as well as just "mysite.com/" ... it might be a security issue? I thought, if my htaccess is properly configured, the "public/" should always be hidden, yea?
The htaccess file in the root folder looks like this:
The one in the public/ folder looks like this (I think it's identical to the symfony repo):
Howdy Matt! The
publicdirectory should be the base orDocumentRoot(Apache) directory in your configuration. Anything inpublicis meant to be exposed to the world. E.g. when you gotohttps://some-site.comthat should point directly to/some/path/publicThey most important thing is that you do not want to be able to access say
https:://some-site.com/.envorhttps://some-site.com/src/Entity/User.phphttps://symfony.com/doc/current/setup/web_server_configuration.html has a few more examples of setting up Symfony w/ Apache, Nginx, etc...
I hope this helps!
Hello,
I use an ajax request with jquery to get my data from Data Base and when,
I switch from APP_ENV=dev to APP_ENV=prod, I get an undefined response.dataClubInfo from my controller JsonResponse.
I have in particular this error:
Uncaught TypeError: Cannot read properties of undefined (reading 'nomClub')
at Object.success (infoClub.js:31)
at fire (jquery.js:3500)
at Object.fireWith [as resolveWith] (jquery.js:3630)
at done (jquery.js:9796)
at XMLHttpRequest.<anonymous> (jquery.js:10057)
What may be the issue ?
Hey Thomas-34
I believe you forgot to clear production's cache. When in production, the cache does not get cleared automatically, you need to do it yourself. Give it a try and let me know if the problem persists
Cheers!
Thank you very much for your quick answer diego but the problem don't seems to come from the cache. I've runned my project from a brand new clone coming from my git repo, and even done a "bin/console cache:clear" and still have an undefined variable when switching from dev to prod.
That's interesting. The error only happens when you switch to production, right? If that's the case, I'd check the followign
yarn build@diego
Thank you, I dindn't think about my dependecies.
It didn't work but I am on a track:
When using postman, the request to my controller give me 2 things:
1:
<script> Sfdump = window.Sfdump || (function (doc) ...... </script>
=> it' what I can read when doing console.log(response);
2:
{"dataClubInfo":{"nomClub":"......}} with my preciouse data !
=> it's the response I get from my controller return new JsonResponse(["dataClubInfo"=>$retourClubTab]);
To resume on dev I have an objet with my data ( {dataClubInfo: {…}} ) and in prod I get no data but :<script> Sfdump = window.Sfdump )
I hope you'll be able to help me now.
Thanks
The answer is beacause I didn't comment all my dump() before return new JsonResponse in my controller.
https://github.com/symfony/...
Thanks
Aha! I knew something was off there. Cheers!
I seem to have lost the certificates, again, after switching to production, but this time I cannot get the localhost to load - it's not secure - Your connection is not private
Hey Tom,
Do you have problems with with certs on the localhost? You can reinstall them. Try to stop your web server, do "symfony server:ca:uninstall", and then "symfony server:ca:install". Look for the output for any errors/warnings. Of everything is OK - then start your server again.
I hope this helps!
Cheers!
When I switch to the prod environment, I get an "500 Internal Server Error".
symfony server:logreveals that the ExceptionListener class was not found.
[PHP-CGI ] {"message":"Uncaught Error: Class \"Symfony\\WebpackEncoreBundle\\EventListener\\ExceptionListener\" not fistener\" not found","code":0,"file":"C:\\Users\\tbrem\\source\\repos\\cauldron_overflow\\var\\cache\\prod\\ContainerX13osoQ\\getWebpackEncore_ExceptionListenerService.php:20"}},"level":500,"level_name":"CRITICAL","channel":"php","datetime":"2021-05-14T12:46:49.632095+02:00","extra":{}}What could be the issue?
Hey Tao Man
Did you cleared the production's cache? When on production, you're now in charge or clearing the cache everytime you make a change. Give it a try and let me know if you keep having problems
Cheers!
Hi i did try it but it didn't work
Hey Badii
Could you tell me more about your problem? and sorry for my late reply
Thanks for the cool courses in here!!
Regarding environments I wanted to ask, what role the use of app.php or app_dev.php plays in here and how do we use different .env files (env.{env}....).
(Sorry about the open question)
Hey Abel,
Thank you for your interest in SymfonyCasts tutorials and kind words about courses!
Hm, good question! If you're a new in Symfony - you probably know only one front controller called "public/index.php" in Symfony projects where the environment of the application is controlled via env vars: real env vars that you can set in your console, or "fake" env vars taken from .env files. Generally speaking, if you need to change the env - you just need to set the correct value to APP_ENV env var.
But before .env files there were parameters.yml files in Symfony projects, and projects had more than 1 front controller. Usually, as many as number of environments existent in your app - they helped to load the website in the specific environment easily. E.g. app.php loaded the website in prod, where app_dev.php as you can guess already loaded the website in dev mode. If you look at those files - you will see that environment is hardcoded in those files.
So, in short, before Symfony started using env vars developers used different front controllers to load the website in different environments: prod, dev, test, etc. without changing anything in the code. But now, since you can control the env with env vars very easily even on the go, there's no reason to keep more than one front controller, that why only the index.php file is kept that works with env vars now :)
I hope this helps! :)
Cheers!
Hi there,
is it possible to launch commands like cache:clear from within the app. That would make deployment a bit easier for me.
Hey @Georg
It's a little tricky, you can do it via symfony/process component which allows to execute shell commands, so you just need run you command programmatically, but it can be pretty unstable. It's totally depends on your workflow, probably if you explain your deploy process and how and when you want to run cache:clear command I'll give you more correct advise =)
Cheers!
Hey Vladimir
I got an account to transfer the symfony files on the production server. The cache/prod directory and the files therein belong to a different user. The hosting service provides an extra web-tool to let me delete cache/prod. Using symfony/process I could delete the cache in my application. However, I understand that deleting the cache with symfony/process from the web application, that is currently using it, might not be a good idea. It's good to know that symfony/process exists anyway!
Hey @Georg!
In case it helps, you can, in practice, "get away with" just deleting the var/cache/prod directory manually. The cache:clear command basically does that, then pre-warms the cache. But if you delete the directory, then the first request after would re-build the cache. It IS possible also to run "commands" (even without the Process component) from inside Symfony... but yea... this one is iffy :). If you deploy some new code, your app might not even run until after your clear the cache (and so, you might be even be able to run your app to run that command) 🙃.
Anyways, let us know if this helps. A lot of the "best ways" to do things depend on how you deploy. If you don't have ssh access to run commands directly, it does make things a bit tricker :).
Cheers!
"Houston: no signs of life"
Start the conversation!