Hi David,

Congratulations on RC2 and again, thank you for all the hard work. When I have 
some time I'll look into the caching. I'll let you know if I bump into any 
problems. It certainly sounds like a cool feature.

Koen 

> -----Oorspronkelijk bericht-----
> Van: [EMAIL PROTECTED] 
> [mailto:[EMAIL PROTECTED] Namens David Zülke
> Verzonden: woensdag 7 februari 2007 21:26
> Aan: Agavi Users Mailing List
> CC: Agavi Dev Mailing List
> Onderwerp: [Agavi-Dev] Finally: Agavi has Caching!
> 
> Hi guys,
> 
> sorry I didn't get to write this mail any sooner...
> 
> Agavi finally has caching!
> 
> 
> It works like this:
> - you create a Foo.xml in module/Blah/cache/ to make 
> FooAction cacheable
> - you put your settings and rules in there
> - you lean back and enjoy the speedup
> 
> 
> Now let's examine the options in detail.
> 
> First, these caching configs have the usual <configurations> 
> and <configuration> stuff at the top level. You should maybe 
> enable caching for "production" environment only since the 
> caches the system writes get thrown away in debug mode anyway.
> 
> Now the top element is <cachings>, which is, as most plural 
> tags that do not require an attribute, optional. In there 
> we're getting to the more exciting things: the <caching> 
> element. Let's have a look:
> 
> <caching method="read" lifetime="2 hours" enabled="false">
> 
> The "method" attribute is optional. It may contain a 
> space-separated list of request method names that caching 
> definition is valid for.  
> You could set up caching for "read" for a complex form, for 
> example, to speed things up a bit.
> 
> The "lifetime" attribute is optional, too. If omitted 
> (omitted means omitted, not lifetime="" !), the cache will be 
> stored forever. You can use any relative format allowed by 
> the GNU date input formats 
> (http://www.gnu.org/software/tar/manual/html_node/
> tar_115.html#SEC115, http://php.net/manual/en/ 
> function.strtotime.php). Examples:
> "1 day 6 hours"
> "3 minutes 14 seconds"
> Note that you can NOT use "thursday 02:00" and other formats, 
> because this would give the same day, and not the thursday of 
> next week, on thursdays after 02:00 o'clock. This is a 
> strtotime limitation, but we might add a fix for that in the future.
> 
> Last but not least the "enabled" attribute. Also optional, 
> and defaults to true.
> 
> 
> Inside a <caching> block, you may define the following elements:
> - <groups> (can be omitted) with <group> elements inside.
> - <views> (can be omitted) with <view> elements containg 
> names of views to cache.
> - <action_attributes> (can be omitted) with 
> <action_attribute> elements containing the names of action 
> attributes to restore when serving a page from cache, these 
> will be available in the view's
> initialize() method.
> - <output_types> (can be omitted) with <output_type> elements 
> that define the layers, slots, request attributes and 
> template variables to cache.
> 
> Important: even when served from a cache, the action and view 
> will still be initialize()d! This is because a view's 
> initialize() method could change the container's output type. 
> If you need an action attribute for that, specify it using 
> <action_attribute>.
> 
> WARNING: Be careful what you include in the cache. 
> <action_attribute> as well as <request_attribute> and 
> <template_variable> (more on these in a minute) can be used 
> to include such items in a cache and restore them when the 
> cache is hit. You might need this in case of request 
> attributes to pass information to a global filter, for 
> instance. But always avoid to cache objects, especially 
> models, propel rows etc.  
> The data is serialized, and in case of models, that would 
> mean that the entire context, and thus ALL objects in the 
> framework are included in the serialization. If you 
> absolutely have to cache objects, implement __sleep() and 
> __wakeup() methods that remember the context name and exclude 
> the context itself from serialization.
> 
> Let's talk about the <view> elements first. If you don't 
> specify any <view>, all views will be allowed to be cached 
> (<views></views>, however, means NO views will be cached,, 
> careful!). You can either give the name of an action's view 
> as you would when returning it from the action, or the full 
> name of a view including it's module:
> <view>Success</view>
> <view module="Admin">AddProductInput</view>
> 
> WARNING: You usually don't want to cache Error views, only Success.  
> Caching Error views would mean that attackers can quickly 
> fill the hard drive of your server by requesting random, 
> invalid pages. You know the drill.
> 
> But now to the most important element: the <group>. Groups 
> work like in Smarty, so I recommend you read 
> http://smarty.php.net/manual/en/ caching.groups.php to 
> understand the fundamental concept.
> 
> Groups may also have a source. You are not limited to a fixed 
> string as a group value. You can use
> - request parameters (very useful and often needed)
> - request attributes (also from namespaces)
> - constants
> - the current locale
> - user parameters
> - user attributes (also from namespaces)
> - user authenticated status
> - user credential (or, rather, if the user has the credential or not)
> 
> I think it's best to give an example here. Let's say we want 
> to cache the page for viewing a product (Default module, 
> ViewProductAction).  
> Each product has an ID, passed in via the request parameter 
> "id". You have i18n in your app, so we need separate caches 
> for each locale.  
> And finally, authenticated users with the credential 
> "reseller" see a special price, so we need different caches 
> for these users:
> <groups>
>    <group source="request_parameter">id</group>
>    <group source="locale" />
>    <group source="user_credential">reseller</group>
> </groups>
> 
> For product ID "3", locale "de" and non-resellers, this would 
> put the cache into:
> 
> app/
>       cache/
>               content/
>                       3/
>                               de/
>                                       0/
>                                               Default_ViewProduct/
> 
> In reality, these directory names are base64-encoded. The 
> last folder will contain a file "4-8-15-16-23-42.cefcache" 
> containing the action information, and one file for each 
> cached output type (e.g.  
> "html.cefcache").
> 
> Now, it is difficult to clear such a cache (more on that 
> later). You might want to cache categories. These have IDs, 
> too. You'd get collisions. Not good. Besides, you cannot 
> easily clear the cache for all products. So we should add 
> another group at the beginning of the
> list:
> <group>products</group>
> 
> Again, remember that the wrapping <groups> element is optional.
> 
> That was easy, wasn't it?
> 
> But that doesn't cache anything yet. We need <output_type> 
> elements, too (yep, the <output_types> container is optional).
> 
> An <output_type> may have an optional "name" attribute to 
> restrict the rules inside to that output type (like the 
> "methods" attribute on <caching>, it can have a 
> space-separated list of output type names).
> 
> Inside, the following elements may occur:
> - <layers> (can be omitted) with a list of <layer> children 
> defining which layers to cache
> - <request_attributes> (can be omitted) with a list of 
> <request_attribute> elements containing names of request 
> attributes to store in the cache
> - <template_variables> (can be omitted) with a list of 
> <template_variable> elements holding names of template 
> variables that are stored in the cache (and then available to 
> all layers that aren't cached and thus rendered even on a cache hit
> 
> I'll explain <request_attribute> first:
> 
> <request_attribute
> namespace="org.agavi.filter.FormPopulationFilter">populate</
> request_attribute>
> 
> Will store the attribute "populate" from the namespace 
> "org.agavi.filter.FormPopulationFilter" and restore it when 
> the cache is read. In our example, this attribute would 
> contain a ParameterHolder object with fields to populate. 
> Obviously, you should only use that for the "read" request 
> method to fill initial values into your form. A bit of a 
> stupid example, since you'll often have default values (like 
> "[EMAIL PROTECTED]" or a checkbox pre-selected) in the 
> template itself, but who knows. You get the idea.
> 
> Next, layers. For this example, we assume that out current 
> view has two layers - "content" and "decorator".
> 
> To cache everything, you simply don't define any layers.
> 
> To cache only the "content" layer, you'd do <layer 
> name="content" /> Then this layer and all layers inside will 
> be cached. The "decorator"  
> layer would still be rendered on each request.
> 
> That puts you into trouble - you have the "_title" template 
> variable you want to output in the decorator, in the html 
> <title> element. But since the view is not executed anymore 
> when a cache hit occurs, we have to tell the caching engine 
> to store this template variable along the content and then 
> restore it before the decorator is rendered.  
> Easy task:
> <template_variable>_title</template_variable>
> 
> Now back to the layers. Instead of
> <layer name="content" />
> you could also have done
> <layer name="decorator" include="false" />
> 
> That would exclude the layer from the cache, and include all 
> layers inside. Surprise surprise, that is actually the better 
> way of doing it! Simple reason: your view _might_ insert 
> another intermediate layer (let's call it "wrapper") between 
> "content" and "decorator".  
> That layer should be cached, too (at least we assume that 
> here), but setting the "content" layer as the cacheable layer 
> wouldn't work for that - only that layer would be cached. If 
> we define "decorator" to be the last layer before the cache 
> kicks in, though, we'll achieve that goal and have any layer 
> inside "decorator" in the cache.
> 
> Now let's assume we have that setup, but we do NOT want the 
> "wrapper"  
> layer in the cache. Then we could do:
> <layer name="decorator" include="false" /> <layer 
> name="wrapper" include="false" />
> 
> But now you might ask "hey isn't that stupid, why do I have 
> to declare them both as non-cacheble?", and you're right to insist:
> <layer name="wrapper" include="false" /> does exactly the same thing.
> 
> BUT
> 
> What about slots?
> 
> Here's the nice thing. Obviously, slots set on a layer are 
> included in the layer's cache, since the whole layer output 
> is cached, so the slot output will already be included. But 
> if you have include="false"  
> on a layer, then the slots in it will NOT be included in the 
> cache, since the layer is rendered each time.
> 
> But of course, we can include slots in a cache, even if their 
> layer is not cacheable:
> <layer name="decorator">
>    <slot>menu</slot>
> </layer>
> 
> This will include the "slot" layout in the cache
> 
> Note: I omitted the "include" attribute, since declaring 
> slots inside a <layer> automatically sets include to false 
> (unless you provide it and set it to "true", of course).
> 
> Note2: I didn't specify <slots>, but you can, if you like.
> 
> Note3: The order of layers in the configuration does not 
> matter, unlike in the layout configuration in output_types.xml.
> 
> And now the above example with duplicate layers makes sense again:
> <layer name="decorator">
>    <slot>menu</slot>
> </layer>
> <layer name="wrapper" include="false" />
> 
> Of course, every layer can specify slots it wants to cache. 
> Also, if you do not want to cache a slot inside the calling 
> cache, you can of course set up a caching xml config for the 
> slot action itself.
> 
> Tip: Agavi stores cookies with a lifetime, not with an expiry time.  
> Thus, you can cache actions/views that set a cookie on their 
> response, it's not a problem and works just fine! The same 
> goes for all other response headers you set. They are all 
> included in the cache and restored afterwards. You can even 
> set a stream as the resource content, e.g. 
> $this->getResponse()->setContent(fopen('/path/
> to/image.png', 'rb')); - that file will be re-opened when the 
> cache is read and, like all streams set in the response, output using
> fpassthru() for maximum performance.
> 
> I hope that helps a bit. I'm sure there will be many 
> questions from now, and of course, caching will be covered 
> extensively in the documentation, on which we will focus from 
> now on. Just shoot a mail to the users list if find something 
> confusing, or drop by on the IRC channel.
> 
> Cheers,
> 
> 
> David
> 
> 
> P.S: yup, RC2 is really coming tonight! It's only a matter of 
> hours now.
> 
> _______________________________________________
> Agavi Dev Mailing List
> [email protected]
> http://lists.agavi.org/mailman/listinfo/dev
> 

_______________________________________________
Agavi Dev Mailing List
[email protected]
http://lists.agavi.org/mailman/listinfo/dev

Reply via email to