How to disable cache in symfony - php

I am developing a website in symfony framework. In my cache folder a huge cache is stored. I want to disable cache permanently.

While I advise against disabling the cache on a production system, you can disable the twig templating engine cache, by editing and adding to your config.yml file
twig:
cache: false

The class cache in Symfony2 can be disabled in you app.php or app_dev.php file:
$loader = require_once __DIR__.'/../app/autoload.php';
Debug::enable();
$kernel = new AppKernel('dev', true);
#$kernel->loadClassCache(); // <-- comment out this line
$request = Request::createFromGlobals();
Symfony2 - Disabling the Bootstrap File and Class Caching

I was having caching issues even when using app_dev.php. I would change a route but it wouldn't update when I tried accessing it via a browser.
I tried commenting out the anything that had cache in it (as stated above). My AppKernel('dev', true) was set to true. Nothing worked.
If I ran the console cache:clear it would fix it, but the next routing change would break again. I had to run cache:clear with every save, which was ridiculous.
My issue turned out that because I was working remotely over SFTP, PHP Storm (my editor) was "preserving timestamp" in its deployment configuration. Once I changed that configuration the issues went away. Apparently there is some caching going on that is looking at the file timestamps, even in the dev environment.

I think you can't disable "permanently cache", since Symfony applications use some cached files in order to run faster (or simply to run). Examples of this are the files that contains the dependency injection container (appProdProjectContainer.php).
You can disable some types of cache like Twig cache (as Diego Ferri said before) or Http Cache (unwrapping AppKernel with AppCache in app.php) or even Doctrine cache (in config.yml).
However I would not recommend this. The more you cache the app, the faster your app will be.

When you are working in a dev environment state, the cache is disabled anyway - I'm assuming you only want to have it disabled within development, so use the /app_dev.php file to make sure nothing is cached.
Alternatively you can empty the cache periodically on the command line using
php app/console cache:clear
You can see all the different parameters here: http://symfony.com/doc/current/cookbook/console/usage.html

This is from symfony documentation:
https://symfony.com/doc/current/bundles/override.html
If you add a template in a new location, you may need to clear your
cache (php bin/console cache:clear), even if you are in debug mode.
That means that the rules how and when the cache is cleared is not even clearly defined in the documentation.
Sometimes you want to change and debug files in vendor folder and after that even this command will not help you:
bin/console cache:clear
The only thing that will help you is to delete all content inside /var/cache/dev folder
A dirty hack for your local environment which you can use to clear cache after each request is:
<?php
namespace App;
use Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Kernel as BaseKernel;
class Kernel extends BaseKernel
{
use MicroKernelTrait;
public function terminate(Request $request, Response $response)
{
system("rm -rf ".escapeshellarg('../var/cache/dev'));
return parent::terminate($request, $response);
}
}

Related

Error if not clearing cache after deployment

In my Laravel app, I sometimes want to pull the latest version from GitHub without clearing the cache first.
So I just do:
git pull origin staging
But every time I do this and then open the page in the browser, I get this error:
ErrorException (E_WARNING)
file_put_contents(/path/to/laravel/storage/framework/cache/data/30/6c/306cbe845aa9840ab0c14a1cd4b5d83fd6728839): failed to open stream: Permission denied
However, if I just do php artisan cache:clear this issue doesn't happen.
This isn't ideal because I'd sometimes like to keep the cache when I pull changes from Git. We use caching extensively (on every request) and it's a performance issue if we have to clear it on every update.
For example, the last time this happened, my only change was to a View file. No need to mess with the existing cache.
How can I pull changes from Git without clearing the cache and without encountering errors?
My storage folder lives outside the laravel folder. That way I can keep the cache and log files when I update my project.
For this I'm using a custom app where the storage path is defined in the .env.
<?php
namespace App;
use Illuminate\Foundation\Application;
class CustomApp extends Application
{
public function __construct($basePath = null)
{
parent::__construct($basePath);
$this->afterLoadingEnvironment(function () {
$this->useStoragePath(env('STORAGE_PATH', storage_path()));
});
}
}
The issue may be someone committed a logfile into the repository. Follow these
Give Permission to storage file.
Navigate to project folder in terminal
And run chmod -R 755 storage/*
check .gitignore contains /storage/logs path.
Not only on your side on everyone who works in the same repository.

Laravel Environment Variables(without default value passed in method) not working inside Artisan Command file

I am using Laravel 6.x for client's project wherein I have built an API in the Artisan Command for syncing data.
Now client wants the configuration to be discreet, out of main source code and without any fallback values as possible. That means I must define the configs in the .env file and use the env() method without any fallback default values.
This must be possible inside Laravel Artisan command class files, but it is not working as intended when I use the env method in the code as below:
[siteroot]\.env:
APP_ENV=local
[siteroot]\app\Console\Commands\SyncSomeData.php:
use Illuminate\Console\Command;
class SyncSomeData extends Command
{
/**
* The name and signature of the console command.
*
* #var string
*/
protected $signature = 'sync:some-data';
/**
* Create a new command instance.
*
* #return void
*/
public function __construct()
{
parent::__construct();
}
/**
* Execute the console command.
*
* #return mixed
*/
public function handle()
{
exit(env('APP_ENV','staging1'));
}
}
This always prints staging1 in console and if I use this instead of the given env method, then it prints nothing:
exit(env('APP_ENV'));
As I know and can trust that Laravel is most secure, there must be way to have env method work without fallback value in the command file, can anyone help fulfilling this ?
There are a couple parts to this answer.
Caching Config
The issue in this question is only present if you have cached your config on your local environment. If you have ever run php artisan config:cache or php artisan optimize, you have cached your config.
As a result, laravel will no longer read your .env file and load all values for config and .env from cache.
It is best practice, to not use env() throughout your application but create config files for these values. This will speed up your application in production. If you want to take advantage of config cache, you CAN NOT use env() anywhere but in your config files.
In your local environment, the documentation recommends you should not be caching your configuration, since it will be updated frequently. I think this is good advice with one caveat: env(). If you aren't caching your config on local, but are in production, you won't come across errors like the one that was the impetus for this post in local. If you have a ci pipeline and good testing practices than this hurdle is overcome.
If you stick with cache config in local, every time you update your config files or your .env file you will need to run php artisan config:cache.
Disabling config cache
By running php artisan config:clear or removing /bootstrap/cache/config.php laravel will no longer to attempt to read config from cache, and .env will work outside of config files. If you do this, as I stated in (1) make sure there is a part of your pipeline that will catch these errors, if you are caching config in production.
After more discussion with OP, I will make one more thing clear:
Cache config does not automatically just cache your .env keys so you can access them like config('SOME_CUSTOM_DOT_ENV_KEY'). When using cache config, if you need to access environment variables inside of your application, you must reference them in a config file.
Again, once config cache is enabled,.env becomes useless, but it is used to build the cache.
So if you in .env say:
GOOGLE_API_TOKEN=xxxx
You would maybe create a config file like:
google.php
return [
'api_token' => env('GOOGLE_API_TOKEN', 'some-default-value'),
];
And in your application, you will only reference config('google.api_token') and never env('GOOGLE_API_TOKEN').

Symfony 3 web front controller with env

Symfony 3 uses two web front controllers app.php and app_dev.php. How could I change it to use one controller with usage of env variables to set the env (prod, dev) and debug.
I've tried to remove the app_dev.php but symfony tries to load that file.
Maybe this is not the way to do it, just learning symfony. Other suggestions are welcome.
The frontend controller files app.php and app_dev.php exist as examples of prod and dev respectively. As the documentation (http://symfony.com/doc/3.4/configuration/environments.html) suggests, you'll want to remove one or the other for your production deployment, or simply create a custom frontend controller for each environment, and have your apache or nginx configuration only load the appropriate file to launch Symfony.
You'll see in the file, the environment is declared and passed along with whether or not debug should be enabled.
//dev environment, with debug enabled
$kernel = new AppKernel('dev', true);
By contrast, for production:
//prod environment, debug disabled
$kernel = new AppKernel('prod', false);
If you want a single controller with some dynamic elements, I'd recommend removing app_dev.php and using app.php with custom logic before AppKernel is instantiated to do what you want.

Trigger Symfony cache, assets, styles refresh over HTTP

I am working on a Symfony 2 WebApp. The WebApp has been online for about two years, now I would like to update the design. This work should be outsourced to a 3rd party designer.
The designer should be able to work an a live version of the WebApp (= actually running on my server instead of just plain files) so that design changes become visible instantly when refreshing the browser. Thus the designer needs to be able to change/add files directly on the server and to refresh the cache, assets and styles (using SASS + Compass) when ever needed.
At the same time, the designer should not have general access to neither the WebApp code nor the server itself.
Giving access to the design files only is already solved: I have moved all necessary files/folders from the Symfony installation to a separate folder that is accessible by FTP by the designer. Within the Symfony installation the files/folders have been replaced by symlinks (see my question here).
This works great. Only problem is, currently cache/asset/style refresh can currently only be triggered by direct access via SSH:
$ php app/console cache:clear --env=prod --no-debug
$ php app/console assetic:dump --env=prod --no-debug
$ compass compile --output-style compressed --force
Is it somehow possible to expose these commands via HTTP(S)? Of course the designer will be working on a dedicated Symfony installation. Thus changes will not have any effect on the live version.
Problem is, that app/console... is outside the domain root of the WebApp. Of course I could set another domain to point to app/console... But this way all other files and folders below this dir would be accessible as well.
Additionally I am not sure, if compass compile... can be run from HTTP at all. How can this be done?
I am aware, that refreshing cache and assets is not absolutely necessary when using the dev front controller (.../app_dev.php/...) but without able to refresh / re-compile the Compass and SASS files, style changes will not become visible.
So: Can this be done by HTTP? Maybe using some proxy-script that is called by PHP?
To expose these commands via HTTP(S), you can add for your designer a route calling an action in a controller to run the PHP commands, as explained in the doc:
// src/AppBundle/Controller/CommandController.php
namespace AppBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Console\Application;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Output\NullOutput;
use Symfony\Component\HttpFoundation\Response;
class CommandController extends Controller
{
public function refreshAction()
{
$kernel = $this->get('kernel');
$application = new Application($kernel);
$application->setAutoExit(false);
$input = new ArrayInput(
array(
'command' => 'cache:clear',
'--env' => 'prod',
),
array(
'command' => 'assetic:dump',
'--env' => 'prod',
),
);
// You don't need the output
$output = new NullOutput();
$application->run($input, $output);
$content = "Refreshed";
return new Response($content);
}
}
For the compass command, you can use assetic:watch as mentioned in giorgio comment.
I think that it would be best to hide as many things as possible to make it simpler for 3rd party to work with your project. Therefore I'll suggest to handle that automatically behind the scenes.
Therefore:
SASS - I would run Gulp/Grunt watch task server-side that would recompile SASS files on each save. That should work flowlessly. (I'm LESS user, but I guess that works pretty much the same in SASS)
cache:clear - I would recommend you to simply turn off the cache on the instace that the 3rd party will work on. It can be done in a few ways. You can set app_dev.php as entry point instead of app.php, but then you should turn off profiler. You can create separate environment if you don't want to change dev one. Also you probably can change prod configuration.
assetic:dump - I personally don't like Assetic and don't use it, so I may be wrong in this case. Anyway, as I read here, in dev environment there's no need to dump assets as they are delivered dynamically, so the solution for cache issue should work here too.
I use SVN for that, the repo is on our server, the website is a checkout folder and the designer has also a checkout folder.
Make a cron that will make a svn update . and a cache:clear
With that you can grant him access only to the views and maybe controller.
You hide parameters and services and entity from him.
And this is for sure NOT IN PRODUCTION but in integration server

Laravel 5.1: Cannot redeclare class Illuminate\\Contracts\\Support\\Arrayable

I am getting an error message in my Laravel 5 application:
PHP Fatal error: Cannot redeclare class Illuminate\\Contracts\\Support\\Arrayable in /var/www/.../bootstrap/cache/compiled.php on line 156
This error only occurs on my staging environment and not on my local website. I would love to post more info but I do not have it. Because I do not know where this error is caused.
If I remove the file (cache/compiled.php) everything seems to work fine. But after every deploy the same error occurs. On my localhost everything works fine as well.
My question: does anybody have a clue where to look because I am out of ideas.
Try this way.
At first remove the cache/compiled.php file
then run this command
php artisan clear-compiled
I had the same problem and found the following article, which was very helpful:
https://sentinelstand.com/article/laravel-5-optimization-commands
The only solution that was working for me was manually deleting bootstrap/cache/compiled.php. Switching around the order in which the autoloaders are called in bootstrap/autoload.php did not work for me because I had the same problem the other way round, ie. I had a class in compiled.php that was causing something from autoload.php to be autoloaded before autoload.php ran.
In my case, I am using a combination of PSR4 and manual class mappings in my composer.json file. I'm sure this is part of the problem. (Don't judge me: this app started in Laravel 3, so it's taking time to add namespacing throughout the code base :-).
One reason why things may work differently in different environments is because the artisan optimize command will only generate the bootstrap/cache/compiled.php file if you provide the --force option or if debugging mode is not enabled. So it is likely that you are not getting this file in development because debugging is enabled but are getting this file in staging and/or production because debugging is not enabled.
Ultimately, here's what I have landed on as a solution for production deployments:
artisan config:cache
artisan optimize
rm bootstrap/cache/compiled
Update symlink to point to new version.
This way you still get bootstrap/cache/services.json, which is helpful, whereas artisan clear-compiled removes that file. Also, there will be a very brief period of time where bootstrap/cache/compiled.php will exist, which is why it is important to run these commands before you update the symlink to point your web server at the new version.
It is also worth noting that the compiled.php file that is created by artisan optimize in Laravel 5.1 is no longer generated in Laravel 5.4 because, as Taylor has stated, PHP 7 is much more performant and so the benefit of bundling all the application classes into one file, which is meant to save on disk I/O, is negligble now. Taylor recommends enabling and properly configuring your OPcache instead - you will get far more performance benefits from that.
I experienced the same but eventually found the solution.
I have my own helpers.php files in laravel. Just like the framework ones, I added them as autoloads in my composer.json. A couple of those functions are macros for the Collection (\Illuminate\Support\Collection::macro(...)).
When that helpers.php file is autoloaded, the definition of those macros cause the autoloading of Illuminate\Support\Collection. This in turn uses Illuminate\Contracts\Support\Arrayable.
So basically all of these are already loaded by the time they are defined again in cache/compiled.php. Boom.
Long story short: For me the fix was simply to switch inclusion of the compiled file and the autoloader around.
bootstrap/autoload.php:
$compiledPath = __DIR__.'/cache/compiled.php';
if (file_exists($compiledPath)) {
require $compiledPath;
}
require __DIR__.'/../vendor/autoload.php';
This might not be a viable solution add include code in your compiled file runs right away and refers to helper functions, but I think the chances on that happening should be pretty minimal.
The problem is with the artisan optimize command. If you remove the compiled.php file and then do not run optimize, it should work.

Categories