Symfony2: disable Twig cache - php

I'm trying to disable twig cache in prod mode, or to force it to recompile my views.
I'm using KnapLaps SnappyBundle to generate some PDFs (the same problem appears with DomPDF), and I have dynamic content to render.
When in dev mode, I can modify some text, or even some css properties, the changes are effective immediately.
But in prod mode, I need to cache:clear, or to rm -rf app/cache/prod/twig/* to see the changes.
I tried the following options in my config.yml for Twig section (not at the same time)
cache: "/dev/null"
cache: false
auto-reload: ~
I also try some stuff with header when generating and redering my pdf:
$html = $this->renderView("xxxxPdfBundle:Pdf:test.html.twig", array("foo" => $bar));
return new Response(
$this->get('knp_snappy.pdf')->getOutputFromHtml($html),
200,
array(
'Cache-Control' => 'no-cache, must-revalidate, post-check=0, pre-check=0',
'Content-Type' => 'application/pdf',
'Content-Disposition' => 'attachment; filename='.$file
)
);
I can't figure out how to force twig to recompile or not use the app/cache, because obviously the pdf content will be dynamic when in production.
Info update from the comments:
I perceived that even the dynamic template variables were not updated, so the same PDF got generated over and over again in production, but not in development.
After clearing all caches again, that issue is fixed: PDFs are now generated with dynamic content as designed.
Still, a question remains: what if, when my website is in production, I decide to change the CSS styling inside a pdf template ? CSS is not template variable, and I can't force people to empty their cache :/

The correct way to disable Twig's caching mechanism is to set the cache environment parameter to false instead of a cache directory:
# config_dev.yml
# ...
twig:
cache: false
References:
Twig Environment Options
TwigBundle Configuration

The question of client-side caching has some answers.
First, HTTP employs some headers that describe to the client how to do the caching. The worst of them is to declare that the received resource should be considered cacheable for the next time X without revalidating for updates. The less intrusive version is to add a header with a signature of the delivered version or a last-modified timestamp, and the client should revalidate every time whether or not the resource is still up to date, before using it.
The first kind of caching can only be updated by deleting the client cache in the browser. The second could probably be circumvented by force-loading the page again (Ctrl-F5 or so), but this really is as hidden as the menu allowing to clear the cache.
To play it safe, the usual approach would be to add a tag, revision number, incremented counter or whatever is available, to the query string of the URL used for that resource.
http://example.com/generated/summary.pdf?v=1234
http://example.com/generated/summary.pdf?v=1235
The first URL is from deployment run 1234, the second is from 1235 - this number changes the URL enough to trigger a new request instead of getting the old version from the cache.
I don't know if there is something available in your system to act like this. You could also always add an ever changing value like the current timestamp to avoid caching at all, if you cannot disable the HTTP caching headers.

Related

HTML/PHP/SQL - Save a HTML page

Currently I'm working on an application and i have a problem. I want to display an html page but the probem is : there is a lot of data/query behind the page. Is it possible to save the html page with the data every morning and then display the html page saved ? I dont want to load the data every time I load the page because the loading is really long.
I'm working with ZendFramwork and Oracle.
You can use either local storage or session storage for this.
HTML web storage provides two objects for storing data on the client:
window.localStorage - stores data with no expiration date
window.sessionStorage - stores data for one session (data is lost when the browser tab is closed)
Use this link to learn more (https://www.w3schools.com/html/html5_webstorage.asp)
You can use GitHub Pages, write a script in any language to send data in GitHub web page on your decided time and all done your html page in dynamic but act as a static and loads in no time
I think you want to use frontend cache.
There are at least 3 versions of Zend Framework, but the caching si very similar.
For Zend 1 there is some theory https://framework.zend.com/manual/1.12/en/zend.cache.theory.html#zend.cache.clean
Best way is set frontend cache in routes
For that, use this in your router definition file
addRoute($router, [
'url' => "[your-path]",
'defaults' => [
'controller' => '[controller-name]',
'action' => '[action-name]',
'cache' => [TIME-OF-CACHE] // 2 hours = 7200
]
]);
Then, if you really want to delete this cache every morning, you should do it manually, by some CRON script.
For that, try to use this
Zend Framework Clearing Cache
Here is the solution:
You need a cron job that runs the script (the HTML file) every morning
Add ob_start() to beginning of your HTML file
Save the buffer into a file :)
<?php
ob_start();
// Display that HTML file here. You don't need to change anything.
// Add this to the end of your file to output everything into a file.
$out = ob_get_contents();
ob_end_clean();
file_put_contents('cached.html', $out);
?>

Disable Cache in TYPO3 in a USER_INT function

I am working on a TYPO3 project where I have to dynamically disable caching based on a condition. It is a very specific usecase, that will not happen a lot.
I planned to use a USER_INT function, where I would perform the check and disable the cache if necessary. The USER_INT function works flawlessly, it is being called on every page load.
The thing is, I can not disable the cache, or at least I do not know how.
The code, I have right now:
page = PAGE
page {
typeNum = 0
adminPanelStyles = 0
11 = USER_INT
11.userFunc = [COMPANY_NAMESPACE]\PageHandler->checkCache
And in the function I perform the check:
public function checkCache($content,$conf){
global $TSFE;
$id = $TSFE->id;
if($this->checkIfDisableCache($id)){
//$TSFE->set_no_cache(); // <---- first I tried this one
$TSFE->no_cache=true; // <-----after a while I got despoerate and tried to disable it directly
}
}
I also tried to play with the config, it did not work.
The funny thing is, if I set it directly in typoscript:
config.no_cache = 1
it works, but since the check is rather complex, I want to use PHP to determine, if the cache should be disabled.
I know I am doing something wrong, I just don't know what. Any help would be appretiated :)
I don't think either of the previous answers really explain the situation. You have sort of a catch-22 here, in that your USER_INT is executed after the page cache entry has been generated. The way it works internally is everything that can be cached gets rendered first, and every USER_INT then outputs a marker in the HTML source which gets replaced afterwards. This way the cache can contain the version with markers and those can be rendered without having to render the whole page.
So what you need to do in this case if you want the page cache to be disabled only in some conditions, is to use a custom TypoScript condition that is capable of setting config.no_cache = 1 only under special circumstances. That way you prevent generating a cache entry if the condition is met, but preserve full caching and cached output for every other request.
https://docs.typo3.org/typo3cms/TyposcriptSyntaxReference/TypoScriptParserApi/CustomConditions/Index.html
Note that it is still recommended that you instead create the parts of your page that must not be cached, as USER_INT objects. Having a use case where you in some cases need to disable the entire page cache indicates a possible misunderstanding of how the caching framework and/or USER_INT works. Hopefully the above explains those parts a bit.
if you look at the pibase (AbstractPlugin) code you will see that probably setting $conf['useCacheHash']and $conf['no_cache'] should be done.
https://api.typo3.org/typo3cms/current/html/_abstract_plugin_8php_source.html#l00190
If you create this object as USER_INT, it will be rendered non-cached, outside the main page-rendering.
https://docs.typo3.org/typo3cms/TyposcriptReference/ContentObjects/UserAndUserInt/Index.html

Manipulate response via controller to force no cache

I have an ZF2 PHP app and i want my page never put in cache and force the browser to get a new one each time.
First : how manipulate response through controller (ZF 2.4) ? My search fall on older version, often the 1.x and so one. Maybe i miss a thing.
Second : have you an advice about the 'browser never cache' manipulation to do ? On php.net they are a lot of solution but in pure PHP, maybe you know a good way with ZF2.
Thanks, have a nice day
You can access the headers through the response object as follows from a controller action:
$this->getResponse()->getHeaders()->addHeaderLine('Cache-Control: no-store, no-cache, must-revalidate, max-age=0')

Laravel 5.1 Object oriented ajax response caching

I'm working on a Laravel 5.1 project, using a lot of ajax calls returning html blocks.
To optimize the speed of the website i want to implement private and public response caching. this works fine using following code:
return response()
->json($result)
->header('Cache-Control', 'public, max-age=300');
Yet using it this way wont hold in account objects that are updated within the 300 seconds.
Are there possibilities that allow me to clear the response cache of a request, if and only if the returning objects have been updated ?
Maybe you can try server side caching with something like this below. sorry this is crude
function sometest(User $user)
{
/** . . .conditions to check if some data has changed . . . **/
$jsonResponse = Cache::remember(Auth::id() . "_sometest", 300, function () use ($user)
{
$result = $user->all(); //get result here
return $result;
});
return response()->json($jsonResponse);
}
You can read about here Cache
you can also try
config caching: php artisan config:cache
route caching: php artisan route:cache
and utilizing memcached if you are able to.
As other said, client browser need a request to know that the data has been updated. Here's some solutions I would look into in your case:
Server-side cache (data still need to be network transferred):
depending on your environment, I would set up an Nginx + FastCGI cache using a "stale and update" policy. So the cache is always served (fast), and the cache is always refreshed. So only a few requests (one, or more depending on time to refresh cache) after code update are served with outdated data. This cache is URL-based, so if your content is cookie/session-based it can become tricky.
as #ZachRobichaud said, you can use the Laravel cache and set up a low cache retention time. Let's say 10s, which means the request will be outdated for 10s max after your content update. I'm not aware of a "stale and update" way on laravel, but it can be done with queues.
Client-side cache (no data transfer needed):
as I said, the client needs to know the data has been updated to invalidate the cache.
Usually for assets, we do "cache bursting" by adding GET parameters to the file URL. Like 'asset?version=1234with version changing for each deployment. As header cache is URL (and header) based, URL change will force network loading of files. Not tested with text/HTML content-type response, but worth a try if you can update URLs with a parameter you can change in.env` as example. Can be done dynamically if you have a CD/CI or thins you can trigger on deploy. In this case, you can "infinite" cache those as the "refresh" will be done by changing the URL parameter.
You can take a look at stale-while-revalidate Cache-Control header value that seems to work the same: always serve cache, and refresh cache if expired (also look at other parameters, can give you ideas). Careful about compatibility on this (no IE or Safari).
The Laravel Cache may be the fastest to implement and test, and see if the results suit you. It depends on the payload size also, if it's huge, browser cache is indeed better. If bandwidth is not the issue, it's mostly server response time: in this case, Laravel Cache would do the trick.

Cache only part of a page in PHP

Is it possible to cache only a specific part of a page in PHP, or the output of a specific section of code in the PHP script? It seems when I try to cache a particular page, it caches the whole page which is not want I want, some of the content in my page should be updated with every page load while others (such as a dropdown list with data from a database) only needs to be updated every hour or so.
If you are talking about caching by the browser (and any proxies it might interact with), then no. Caching only takes place on complete HTTP resources (i.e. on a per URI basis).
Within your own application, you can cache data so you don't need to (for example) hit the database on every request. Memcached is a popular way to do this.
Zend_Cache
I would probably use Zend Frameworks Zend_Cache library for this.
You can just use this component without needing to use the entire framework.
Step over to Zend Framework Download Page and grab the latest.
After you have downloaded the core files, you will need to include Zend_Cache in your project.
Zend_Cache docs.
Have you decided how you want to cache your data? Are you using a file system? Or are you memcache? Once you know which you are going to use, you need to use a specific Zend_Cache backend.
Zend_Cache Backends / Zend_Cache Frontends
You need to use a backend (how you are caching in storage what it is you want to cache) and
You need to use a frontend (how do you actually want to cache.. like using a buffer, or caching function results etc)
Backend documentation: Zend_Cache Backends
Frontend documentation: Zend_Cache Frontends
So you would do something like this...
<?php
// configure caching backend strategy
$backend = new Zend_Cache_Backend_Memcached(
array(
'servers' => array( array(
'host' => '127.0.0.1',
'port' => '11211'
) ),
'compression' => true
) );
// configure caching frontend strategy
$frontend = new Zend_Cache_Frontend_Output(
array(
'caching' => true,
'cache_id_prefix' => 'myApp',
'write_control' => true,
'automatic_serialization' => true,
'ignore_user_abort' => true
) );
// build a caching object
$cache = Zend_Cache::factory( $frontend, $backend );
This would create a cache which makes use of the Zend_Cache_Frontend_Output caching mechanisms.
To use Zend_Cache_Frontend_Output which is want you want, it would be simple. Instead of the core you would use output. The options which you pass are identical. Then to use it you would:
Zend_Cache_Frontend_Output - Usage
// if it is a cache miss, output buffering is triggered
if (!($cache->start('mypage'))) {
// output everything as usual
echo 'Hello world! ';
echo 'This is cached ('.time().') ';
$cache->end(); // output buffering ends
}
echo 'This is never cached ('.time().').';
Useful Blog: http://perevodik.net/en/posts/14/
Sorry this question took longer to write than expected and lots of answers have been written I see!
You could roll your own caching with ob_start(), ob_end_flush() and similar functions. Gather the desired output, dump it into some file or database, and read later if conditions are the same. I usually build md5 sum of the state and restore it later.
It depends on both what caching and view technologies are you using. Generally speaking yes, you can do something like this:
// if it is a cache miss, output buffering is triggered
if (!($cache->start('mypage'))) {
// output everything as usual
echo 'Hello world! ';
echo 'This is cached ('.time().') ';
$cache->end(); // output buffering ends
}
echo 'This is never cached ('.time().').';
taken from Zend_Cache documentation.
Otherwise in your example you can always make a function which returns the dropdown list and implement the cache mechanism inside that function. In this way your page is not even aware of caching.

Categories