Zend how to use cache component - php

Let's say you have this scenario:a simple blog home-page that loads both static content as well as dynamic content.
The static content is composed of images that rarely changes.I also have database-driven,dynamic content.The dynamic content consists in all of your blog posts (text and image) and related users comments.The dynamic content changes periodically from every hour to every day.
How would you go with caching?And in particular supposing a user is leaving a comment or the admin is adding/editing a post to you would want to manually trigger the cache clearing to have the update version of this blog home-page?
thanks for your patience.
Luca
thanks again

First, a link: http://framework.zend.com/manual/1.11/en/zend.cache.html
Basically, what you need to do is set up a cache mechanism and then manually call it when you want to retrieve something from the cache.
In the bootstrap, I might have this code:
public function _initCache () {
$cache = Zend_Cache::factory(
'Core',
'File',
array(
'lifetime' => 3600 * 24, //cache is cleaned once a day
'automatic_serialization' => true
),
array('cache_dir' => APPLICATION_PATH.'/cache')
);
Zend_Db_Table_Abstract::setDefaultMetadataCache($cache); //cache database table schemata metadata for faster SQL queries
Zend_Registry::set('Cache', $cache);
}
Then, you may use the load() and save() functions to manipulate the cache. An example from my controller:
$cache = Zend_Registry::get('Cache');
if (!$this->menu = $cache->load('main_menu')) {
$model = new Model_Menu();
$this->menu = $model->get();
$cache->save($this->menu,'main_menu');
}
Here, I check whether the key "main_menu" is cached. If a cache miss is scored, the main menu is generated and cached.
If I edit the main menu, I'll want to regenerate the cache as well. I simply call this:
Zend_Registry::get('Cache')->remove('main_menu');
It's pretty simple, just read the documentation. It's well written.

Zend cache provide a very simple way to store data in cache and to increase the speed. Zend uses frontend and back end to caching. Front end is useful to access or operate the cache. Back end is useful to store data in File , memcache, Sqlite etc.
First of all initialize the fronted and backed in bootstrap file by creating on function in bootstrap file.
protected function _initCache(){
$frontend= array(
'lifetime' => 7200,
'automatic_serialization' => true
);
$backend= array(
'cache_dir' => '../application/tmp/',
);
$cache = Zend_Cache::factory('core',
'File',
$frontend,
$backend
);
Zend_Registry::set('cache',$cache);
}
Then use the zend cache factory to define the cache object. The parameter core define the zend cache core means of generic type File parameter is to define the cache storage means where to store the records of cache then second and forth is for frontend and backend.
Now register that cache array using zend registry so that you can use that are in any controller , model etc.
Define Below code in any controller or any model where you want to use caching of data.
$result1 =””;
$cache = Zend_Registry::get('cache');
if(!$result1 = $cache->load('mydata')) {
echo 'caching the data…..';
$data=array(1,2,3);
$cache->save($data, 'mydata');
} else {
echo 'retrieving cache data…….';
Zend_Debug::dump($result1);
}
First of all in above code we get the cache array. Now if result one is not set then caching done means the file is generated at the path that you define in back-end array
For the Next time page load that data is retrieve from the file where the caching data store.
You can check the file as per defined path.
In that file data is in json format.

So the basic usage of cache is shown by #mingos. He talks about generic cache, which is good. However, ZF has few different cache mechanisms that you can use for different things. You don't need to limit yourself for one type of cache. You can use a mixture of them. For example, for caching your static content Zend_Cache_Frontend_Page would be worth considering as it would generate a full html file of your static pages. If you have lots of config files, e.g. long routes.ini or whatever, you can cache them using Zend_Cache_Frontend_File. With this you would save time parsing the ini files for every request. Significant parts of your views could be cached using Zend_Cache_Frontend_Output, etc.
What to cache and when to update a cache is a tricky question. It all depends on how fast and how often your content is changing. For example, if you have like 100 new comments per second, there is no point in cleaning your comment cache 100 times per second (i.e. for each new comment). It would be better maybe to have comments for each post cached separately from the comments of other posts. Then you would clean/refresh a cache associated with only this post.

A simple cache is one that times out after the defined period of time. This keeps the caching layer simple and easy to implement. The Zend Manual has more information on caching basics.
However real-time information and cached information are two worlds. If you need real-time, don't cache.
If you make the caching layer too complex, you can destroy your whole application.

Related

How to get data, passed by a view composer to certain views, inside the controller?

My View Composer passes some data to certain views (and it works, of course):
use Illuminate\View\View;
use App\Util\Helper
class PublicSettingsComposer
{
public function compose(View $view)
{
$view->with('settings', Helper::readSettingsFromFile()); // json
}
}
The appropriate provider is added into the configuration and it provides this composer correctly for all specific views:
view()->compose('public.layouts.*', 'App\Http\ViewComposers\PublicSettingsComposer');
However, inside (only) one of my views I need specific information from database, but therefore I have to use some data, that had been passed by my View Composer:
class BranchController extends Controller
{
public function branches()
{
$settings = retrieve_settings_passed_by_PublicSettingsComposer; // This is what I need
$headquartersId = $settings->headquartersid;
return view('public.layouts.branches', [
'headquarters' => Branch::find($headquartersId) // Branch is a Model
]);
}
}
FYI: Laravel version I'm using is: 5.5
P.S. #moderators: Please, be careful with considering my question as a duplicate. I know there are many questions about view composers and passing data to the views and grabbing data from within controllers. However, I really could not find any question with this context (titles are often misleading).
I see two rather simple solutions for this. The first one is to cache the parsed file within each request. The other is to use an actual cache for this job.
The first option is very straight forward to implement. In your Helper class you'll have to introduce a static property to hold the parsed contents of the read file. Then, just like you do within the singleton pattern, you either return the cached data or you first parse the file, cache the data and return it afterwards. This scenario solves your actual problem of parsing the settings twice per requests if used in two places of your app.
class Helper
{
protected static $cachedSettings;
public function readSettingsFromFile()
{
if (!self::$cachedSettings) {
self::$cachedSettings = // Do the parsing here. This should be your current implementation of Helper::readSettingsFromFile(). You can also put this in its own function.
}
return self::$cachedSettings;
}
}
The other option is to use an actual cache (an external one). You can either cache the parsed file for a specific amount of times (like 1, 3, 5 or 10 minutes or even longer). Or you cache it forever and invalidate the cache when you update the settings (if this happens within your app and you know it was updated).
This solution does only make sense if your settings do not change too frequently though. It also depends a bit on the amount of requests you expect towards your app. If your settings change not too frequently (less than every x minutes) and your app is used frequently (multiple requests every x minutes), then it could be a viable solution.
class Helper
{
public function readSettingsFromFile()
{
return Cache::remember(function () {
$settings = // Put your current calculation here
return $settings;
}, 3 * 60); // 3 * 60 = 180 seconds
}
}

Cache for Magento EE 1.9: Should we use full page caching (with hole punching) and/or "classical" block caching?

We are using Magento EE 1.9.
In order to speed up a client website we are trying to fine tune the cache.
As you know
Magento come with differnet cache technique.
In Magento EE we can use Full Page Cache coupled with the technique named "Hole Punching".
As far as I understand this cache used some container to determine
if a dynamic block should be retreive from the cache => applyWithoutApp($content)
or if a dynamic block should be instantiated and rendered using $this->_renderBlock() => applyWithApp($content)
In order to do that you must declare in cache.xml the block you want to be "holepunched" with among other things its proper container class extending
Enterprise_PageCache_Model_Container_Abstract
In this container class you have to implement different function like
_getIdentifier(), _getCacheId(), _renderBlock
As you can see Contanier has is own cache ID.
As explained here
http://www.magentocommerce.com/wiki/5_-_modules_and_development/block_cache_and_html_ouput
to cache a block you juste have to add data directly in the bloc's constructor by defining cache_lifetime,cache_tags,cache_key
class {NS}_{Module}_Block_{View} extends Mage_Core_Block_Template {
protected function _construct()
{
$this->addData(array(
'cache_lifetime' => 120,
'cache_tags' => array(Mage_Catalog_Model_Product::CACHE_TAG . "_" . $this->getProduct()->getId()),
'cache_key' => $this->getProduct()->getId(),
));
}
}
Edit with the fllowing post
http://magebase.com/magento-tutorials/adding-cache-support-to-magento-blocks/
I've understand that static "cache_key" is just not sufficient .
For these cas we should use the method getCacheKeyInfo:
public function getCacheKeyInfo()
{
return array(
'EXAMPLE_BLOCK',
Mage::app()->getStore()->getId(),
(int)Mage::app()->getStore()->isCurrentlySecure(),
Mage::getDesign()->getPackageName(),
Mage::getDesign()->getTheme('template')
);
}
All that said I go back to my questions:
As I understand that FPC + hole punching seems a more complete solution for "caching".
But what is the difference between full page caching (with hole punching) and "classical" block cache ?
-> As We are using Magento EE 1.9 should we only use FPC + hole punching ?
(Because in a way FPC + hole punching is already a way to cache block?)
Does it means that "classical" block caching is just outdated or only dedicated to users of the magento Comunity Edition?
-> or should we use both (FPC + hole punching and classical Block Caching)?
In this case what is the interest to set a cache id for a container when a block has his own cache key (or getCacheKeyInfo()) ?
In this case which one of these cache method is predominant ?
Thanks by advance fo all your answers !
Generally Magento uses a layered approach to caching: if a top level cache doesn't give a hit, then hopefully some low level caches make for a faster build-time for the response.
However, in regards to the Magento FPC, the usual block level caching is disabled automatically. The caching of the dynamic blocks is done on the FCP level. The process nevertheless involves the information from the gatCacheKeyInfo() method to build the cache key (and build a list of parameters for regenerating the block "without the app").
If you are using a different FCP from the EE one, it might well be the case that the usual block caching still can be used as a fall-back level of caching. IMO that approach would make sense.

CakePHP Cache::write() Can keys be grouped by model?

Consider the following;
Cache::write('Model.key1' , 'stuff');
Cache::write('AnotherModel.key1' , 'stuff');
Cache::write('Model.key2' , 'stuff');
Can I delete a group of keys from the Cache?
For instance, if I wanted to clear all cached data for "Model" but leave "AnotherModel" in the cache, I would like to use the following;
Cache::delete('Model.*');
Can this kind of thing be achieved in CakePHP 1.3.x?
Thanks!
For those just Googling this issue (as I was), Cake 2.2 now supports this kind of functionality (without having to create separate cache configs for each 'group').
There is a little explanation here, although it lacks some details:
http://book.cakephp.org/2.0/en/core-libraries/caching.html#using-groups
But this is what I did in my app and it appears to work well. ;-)
In /app/Config/core.php
Cache::config('default', array(
'engine' => $engine,
...
'groups' => ['navigation'],
));
Model afterSave hook:
function afterSave($created) {
// This deletes all keys beginning with 'navigation'
Cache::clearGroup('navigation');
parent::afterSave($created);
}
Then in my controller/model that requires an expensive query...
// We create a unique key based on parameters passed in
$cacheKey = "navigation.$sitemapId.$levelsDeep.$rootPageId";
$nav = Cache::read($cacheKey);
if (!$nav) {
$nav = $this->recursiveFind(
'ChildPage',
['page_id' => $rootPageId],
$levelsDeep
);
Cache::write($cacheKey, $nav);
}
You can set up a different cache config for each model such that each config has a different path.
http://book.cakephp.org/view/1515/Cache-config
I don't see a way to completely delete all data using the cache class but you could write your own function to delete all of the data (cached files) out of the specific cache directory for the specific model. By using different config files for different models, you can isolate the model's cached data into a unique directory for each model and then manually delete the contents when you want to flush the data for that model.

How do I use Zend Cache on this particular problem

I have an action that renders two different view scripts based on whether the user is logged in or not.
class IndexController extends Zend_Controller_Action
{
....
public function indexAction()
{
$auth = Zend_Auth::getInstance();
if($auth->hasIdentity())
{
$this->render('indexregistered');
return;
}
else {
$this->render('indexpublic');
return;
}
}
....
}
I have seen quite some useful examples on how to use the Zend Cache and they seem to be based on the fact that the action renders one particular script.
What am really looking at is the best approach to cache the indexpublic script which gets quite some hits and I would really like to avoid the Zend MVC overhead if possible.
Zend_Cache_Frontend_Output may be what you need here:
if (!($cache->start('indexpublic'))) {
// output everything as usual
$this->render('indexpublic');
$cache->end(); // output buffering ends
}
Before that, the cache manager needs to be initialized (could be in the bootstrap), e.g:
$frontendOptions = array(
'lifetime' => 7200
);
$backendOptions = array(
'cache_dir' => '/tmp/'
);
// getting a Zend_Cache_Frontend_Output object
$cache = Zend_Cache::factory('Output',
'File',
$frontendOptions,
$backendOptions);
You're not likely to "avoid the MVC overhead" in any meaningful way here, since that MVC framework is exactly the context which Zend_Cache lives in. Once you're inside a controller action, you've already used a bunch of resources for routing and setup.
That said, if expensive stuff goes on inside of indexpublic.phtml, you might look into using Zend_Cache_Frontend_Output inside your template to cache a bunch of stuff. If indexpublic kicks off expensive operations (like DB hits), this might be worthwhile. If it's just pure PHP that generates markup, you're unlikely to see much improvement.
Before doing anything, I'd suggest you study your application behavior very carefully and make sure you're optimizing in the right place, and not prematurely.

Zend_Navigation caching

I'm having trouble with the page hierarchy of Zend_Navigation getting scrambled when I cache it using Zend_Cache.
Background: I have approx 50 pages and approx 300 products stored in a database. I query the database and create an array to feed to Zend_Navigation.
The cache is
$secondsBetweenRefreshes = APPLICATION_ENV == 'development' ? 30 : 300;
self::$cache = Zend_Cache::factory( 'Core', 'File',
array( 'automatic_serialization' => true,
'lifetime' => $secondsBetweenRefreshes ),
array( 'cache_dir' => CACHE_PATH . 'nav/' )
);
This works fine
$struct = $cache->load('Zend_Navigation');
if (empty($struct))
{
$cache->save($struct = self::getSiteStructure() );
}
return new Zend_Navigation( $struct );
And this gets scrambled
$struct = $cache->load('Zend_Navigation');
if (empty($struct))
{
$cache->save($struct = new Zend_Navigation( self::getSiteStructure() );
}
return $struct;
The navigation works fine if it is not pulled from the cache. Yes, the obvious solution is not to cache the Zend_Navigation, but the constructor does a lot of work to build its internal representation: makes sense to do the caching with as much pre-computed as I can...
I'm still trying to see if there is a pattern in the scrambled results. There are no loops / cycles in the tree.
After reading this question, I took a quick glance at the Zend_Navigation code and it does not seem that there should be any inherent issues with caching it using serialisation. However looking at the Zend_Navigation documentation I found the following:
The toArray() method converts the container and the pages in it to an array. This can be useful for serializing and debugging.
- Zend Navigation Containers: Other
You may want to create the Zend_Navigation object, use the toArray() function to create the array and cache that. Re-creating the pages from an array should be fairly inexpensive, although you may want to do some testing.
Also, if possible, file a bug report with the Zend Framework maintainers so that they can take a look at it.
Zend_Navigation although an interesting component, and arguably a useful one is not something I use much. For big websites having 10,000+ objects in memory is not a smart idea, and the way certain items are implemented in Zend_Navigation makes it slow and unwieldy. Many developers using the Zend Framework have found other ways of accomplishing the same goals.
Just a warning about caching pages array...
If you cache the array from toArray(), and want to simply use setPages($pagesFromCache), you need to deactive all pages in cached array for future use.
Be careful, Zend_Navigation_Page_Mvc::isActive() checks current request. It means isActive() of your current MVC page still return true, even if you called setActive(false).
The only way I found to deactivate all pages is to recursively walk trough the resulting array :
$pages = $navigation->toArray();
array_walk_recursive(
$pages,
function(&$item, $key)
{
if($key === 'active')
$item = false;
}
);
$cache->save($pages, 'pages');
Thanks for the post; I thought there may be issues combining Zend_Navigation and Zend_Cache, but I've been able to use the save method on a normal Zend_Navigation object and then retrieve the object back from the cache without any need to use toArray().
X-Istence: I agree that as the size of the navigation objects grow, it may become become rather unwieldly; though I'll have to dig deeper in the code to complete my understanding as to the size tipping point.

Categories