Working with caching

60 views
Skip to first unread message

Torkil Johnsen

unread,
Jun 24, 2007, 9:37:10 AM6/24/07
to joomla-d...@googlegroups.com
Hi all,

I'm currently reading up on the APIs and Joomla 1.5 code in general. The transition to Object Oriented code was a bit of a mouthful considering how long it has been since I last worked with this kind of code, not to mention the php4 - php5 differences that one has to look out for.

All excuses aside: I'm working on a component that basically fetches data and displays it. The data is fetched from an external source, so I want to be able to cache these calls since the external source might not have 100% uptime, and since caching would probably speed this component up alot. From building this component I also hope to learn enough to write a basic tutorial on how to implement caching in your average Joomla component.

So far I have concluded that the model is the part of the code that fetches data, hence the model should also handle the caching. (no, to me it wasn't obvious until I had read the MVC tutorial - thanks for that by the way, great read!)

My first question is concerning the JCache descendent classes JCacheCallback, JCacheOutput, JCachePage and JCacheView:

What is the purpose of each of the descendents? To me the class names and descriptions do not give a clear and distinct meaning or description, so being one that hasn't used any of these before, I have to ask... Which class should I use when?

Best regards,
Torkil

torkil....@gmail.com

unread,
Jun 26, 2007, 12:24:36 PM6/26/07
to Joomla! Devel Documentation
I'm really eager to get started, so I'll post some more of my
ponderings:

Looking into JCacheCallback, it might seem as if this would be the way
to go in the controller:

1) Create the model object
2) Call JCacheCallbacks get-function, and use the models desired
function as the callback

So when the controller calls JCacheCallback, it will first look for a
cache item, and if the cache item is not found, then the callback
function is used to re-fetch the data from wherever it is stored
(database for instance).

Does that sound close to right?
I'm still pondering on those other JCache descendants, and when they
should be used.

- Torkil

torkil....@gmail.com

unread,
Jun 27, 2007, 8:06:06 AM6/27/07
to Joomla! Devel Documentation
Ian was kind enough to forward a chat transcription that I will share
with those interested:

<ian> is anybody able to reply to Torkil's message on The Developer
Documentation Discussion list is he can move further with his caching
tutorial?
<ian> or at least point him in the right direction?
<ian> I don't know a lot about caching, so I'm afraid I can't offer
too much help
<tcp> url ?
<tcp> i don't know too much about caching either :)
<ian> http://groups.google.ca/group/joomla-devel-docs/browse_thread/thread/923b7d615064cfd9/?hl=en#
<tcp> k, looking
<ian> thanks
<Willebil> ian: will also take a look
<ian> great...
<ian> would like to get him going to get his momentum going for
writing tutorials...
<tcp> well they're prob called from JCache::getInstance
<ian> are there good examples to point towards for using caching?
i.e. in the core components?
<tcp> JDocumentRendererModule
<Willebil> ian: the content component is an example
<Willebil> combined with the page cacge pluging
<ian> okay... I'll take a look...
<tcp> in com_content, i'm only seeing calls to $cache->clean()
<tcp> an example of how to clean the cache :)
<tcp> i thot there was something in JView
<Willebil> yes, some stuff also has been implemented in the
mvc...Louis can give more details bacause he coded almost all of it
<ian> so it is no longer in com_content?
<Willebil> caching is implemented on several levels, it just is not
in one place
<tcp> oh, JController's display method
<ian> JCache has four descendants: Callback, Output, Page and View...
<ian> which one to use is specified in getInstance, but what is the
difference between them?
<ian> what do they represent?
<ian> would one invoke getInstance? Or is it always done through the
factory?
<tcp> oh, JFactory::getCache is were the magic happens, it looks like
<Willebil> i am pretty sure that is the factory
<Willebil> caching has implemented on the for descendants
<Willebil> output, page and view caching are clear to me, callback i
am not certain
<ian> looks like callback is for caching a function
<Willebil> sounds logical, Louis can be conclusive on this one
<ian> output is a pretty general term... what does it cache? would
would I use it for?
<tcp> looks like callback is for methods
<ian> page would be for caching a whole page, right? so that would be
used by the application
<Willebil> page, yes
<ian> probably not the individual component
<ian> view would be used by JController?
<ian> to cache a specific view of a component
<ian> correct?
<Willebil> yes
<ian> and then output would cache...
<ian> not sure what?
<Willebil> let's ask the professional...Jinx ?
<Willebil> Jinx: is bugfixing, so maybe he can spare some of his
valuable time ;-)
<ian> heh... bugs aren't important, are they?
<ian> :)
<Willebil> they are, but documentation is also important
<ian> I agree... that's why I'm on the documentation team :)
<ian> http://pastebin.ca/590680
<ian> that is the code in JDocumentRendererModule
<ian> It uses the JCacheCallback to cache the resutls of
JModuleHelper::renderModule
<rhuk> try www.paste2.org
<ian> so it looks like that is correct that callback caches method
calls
<ian> is paste2.org better?
<ian> what's the difference?
<ian> okay... I can't find output or page being used anywhere
<ian> everything is callback (which is the default) except for
JController::display uses view
<Jinx> anybody needed me ?
<tcp> i didn't find then neither
<tcp> i think jinx deleted them all
<tcp> :p
<tcp> callback is the default to JFactory::getCache, and I saw one or
two references to getCache('XYZ', 'view')
<tcp> "Under Construction" ???
<Jinx> callback is used to cache a function
<Jinx> it's default for BC reasons
<ian> yep...
<ian> what about output Jinx?
<Jinx> the 1.0 caching system uses cache_Lite pear packages and acts
in the same way as the callback handler
<ian> what is it for?
<ian> will Page eventually be used for caching entire pages?
<Jinx> output is simple, it uses a ob_start and end, everything that
is echo'ed between the start and end is cached
<ian> it doesn't seem to be used at the moment (based on a grep)
<ian> so how would you use it?
<Jinx> page is used by the page cache plugin
<Jinx> how to use output ?
<ian> yeah...
<ian> okay... so the caching invokes getInstance directly instead of
using JFactory...
<ian> is there a reason?
<ian> I guess you can set the options directly then if you use
getInstance, otherwise you use the application defaults?
<Jinx> yeah, that's it, bascially that should be cleaned up
<Jinx> the factory should allow for setting the options
<ian> oh... okay then
<Willebil> i am off for some minutes, papa's time....bbism
<ian> okay thanks Wilco
<Jinx> small cleanup issue in the code
<ian> so with output...
<ian> let me look at the api for a sec...
<ian> so you would invoke start with the id that you want to use to
reference it...
<Jinx> $cache = JFactory::getCache('mygroup', 'output');
<Jinx> $cache->start();
<ian> then you would do your output
<ian> and then invoke end...
<ian> that all?
<Jinx> --- do your won ******** here ---
<Jinx> echo $********;
<Jinx> $cache->end();
<Jinx> done
<ian> okay... gotcha...
<ian> all makes sense now...
<ian> Thanks for clearing that up Jinx!
<ian> hope we didn't disturb you too much!
<ian> I'll pass that on to our doc guy who will write a tutorial
<Jinx> what happens is that if mygroup is in the cache he will echo it
<Jinx> if not you need to create it and he will store it
<ian> so would you wrap that in an if statement?
<Jinx> so output always generates output, either from cache or
dynamically
<Jinx> no
<Jinx> start and end do the iffing
<Jinx> for you
<ian> okay... I'll have to look at the code to see how that works...
<Jinx> oke
<Jinx> looking at the code tit looks like Louis might have made a
small mistake
<ian> it seems to me you would still need an if around the code that
you output...
<ian> so you would do:
<ian> if ($cache->start( 'myid', 'mygroup' )) {
<ian> or rather, if (!$cache)
<ian> then do my output
<ian> else
<ian> do nothing, right?
<ian> so something like:
<ian> http://paste2.org/p/4099
<ian> Jinx? confirm?
* Aristocrat has quit (Quit: Aristocrat)
* Rob (R...@JoomlaNet.6ABB13A5D8E23E.TR) has joined #dev
* Louis (lo...@JoomlaNet.6ABB13A5D8E23E.TR) has joined #dev
* friesengeist (fries...@JoomlaNet.0A78A403955.TR) has joined #dev
<ian> Hi Louis
<ian> (and Rob and friesengeist, lest anybody feel left out :) )
<Rob> Hi ian
<ian> been talking about caching...
<tcp> did i miss a meeting announcement ... ?
<ian> can you confirm...
<ian> http://paste2.org/p/4099
<ian> is that the way to do it?
<Rob> not my area
<Rob> best to ask Johan/Louis
<ian> yeah... I've been talking to Jinx...
<ian> and that's why I tried to get Louis when he came in...
<Rob> he is currently skyping with someone
<tcp> question: re: com_content and displaying articles, should we
leave date formatting to the templates ?
<ian> okay... I'll wait till he's done...
<Rob> tcp: in my opinion, yes
<ian> regarding date formatting.... that's tricky... because should
partly come from language file, shouldn't it?
<tcp> i notice that ContentModelArticle, it uses gmdate() at times,
and other times, no ...
<tcp> @ian: yeah, but where should it happen
<tcp> i'd say the template
<tcp> <?php echo JHTML::_('date', $this->article->modified,
JText::_('DATE_FORMAT_LC2')); ?>
<ian> yeah... but then DATE_FORMAT_LC2 comes from the language file,
right?
<Rob> correct
<tcp> yeah
<tcp> but in the model, it is using gmdate
<tcp> sometimes
<ian> ahhh...
<ian> I thought everything was supposed to use JDate or JHTML::date
<tcp> and it's also setting modified_by to the current user ... ?
<tcp> @ian: i think so, but this is prob some older code
<tcp> ie, two days ago :P
<ian> ha
<ian> modified_by should be set to the current user, no?
<ian> they are the ones who modified it if they are saving it...
<Jinx> ian : that would work
<ian> okay thanks Jinx.
<Jinx> http://paste2.org/p/4099
<ian> Thanks again for your help!
<Jinx> refering to this
<ian> is that the best way to do it?
<Jinx> yep that is the only way :)
<Jinx> with the current code
<ian> current code as in the 1.5 code...
<ian> or are you gonna change it before RC?
<ian> or stable?
<tcp> @ian: oh, yeah, it is in the store() method ... duhhh
<Jinx> naah this is fine
<ian> okay fantastic!
<Jinx> do an if check and be done with it
<Jinx> not going to change any API's if they work

torkil....@gmail.com

unread,
Jun 27, 2007, 10:13:44 AM6/27/07
to Joomla! Devel Documentation
I've been testing this for a while now and I have put the mentioned
caching example to use in one of my view templates. I was hoping to
implement caching on a higher level, like in the model, but this will
do for now:

<?php
// Prevent unauthorized access
defined('_JEXEC') or die('Restricted access');

// get the cache object, create one if it isn't found
$cache =& JFactory::getCache( 'myComponent', 'output' );

// If cache does not exist, start caching
if (!$cache->start( 'myStuffSingleItem'.$this->data[id],
'myComponent' )) {
// Output what needs to be output
echo "Outputting stuff here from the this->data array";
// Stop caching and store the collected data
$cache->end();
} else {
echo "Cache was found and used!";
}
?>

This results in absolutely nothing. The last sentence is never echoed.
I never get any error messages either, so it is hard to tell where
things are going wrong.

I did however make the following observations:
In the API documentation the cache->end function is supposed to give a
boolean return, but the function lacks a return statement, at least in
the api documentation.

I then thought I might need to publish cache plugin but thats just for
page caching, right? Still: Clicking on the publish button or trying
to open the publish plugin to set it to "published" actually broke my
site and created the following error message:
Fatal error: Call to a member function get() on a non-object in /my/
joomla/root/plugins/system/cache.php on line 51

So I dropped that and went back to trying to get cache->end to work.

At this point I realized I had actually forgotten to turn caching on
(duh), but neither activating caching nor calling $cache-
>setCaching(true); gave any further success.

Digging further: $cache->end calls $cache->store to store data, which
in turn send data to the storagehandler. The data sent in $cache-
>store is correct. At this point, no files appear to be stored in the /
cache folder, so caching isn't really doing what it's supposed to. So,
with no data being written, I try making my cache folder writeable...
and voila. That was it. Triple-Duh. I assumed that with the new FTP-
layer in here that it would manage that stuff automatically.

So it was a learning experience, where I have the following remarks to
the people of the devteam working on the cache code:
1) The end user needs to be given some sort of notice when the cache
folder isn't writable. Preferably in the global configuration. Maybe
the cache folder could be made writable if the system already has ftp
access and caching is activated?
2) I get the following error when trying to publish the cache plugin:
Fatal error: Call to a member function get() on a non-object in /my/
joomla/root/plugins/system/cache.php on line 51
3) The function JCacheOutput->end lacks a return statement. According
to the API it should return a bool.

I am also left with the following questions:
1) Does page caching work automatically (JCachePage), even with custom
components, through the cache plugin, or is it just for caching core
Joomla stuff?
2) If I am using output as my caching method, should I implement this
in the model? The example given above with the if block just echoes
some text in between, but echoing isn't done until the template files.
Not the place you'd want to implement caching I guess.
3) In general, it would be good to get a short explenation on what
caching methods to use when. A kind of best-practice ruleset if you
will.

This is my first time really digging into this code, so forgive me if
some of the questions are silly or already have been explained :)

Reply all
Reply to author
Forward
0 new messages