3 package Catalyst::Plugin::Cache;
4 use base qw/Class::Data::Inheritable Class::Accessor::Fast/;
10 use Catalyst::Utils ();
14 use Catalyst::Plugin::Cache::Curried;
16 __PACKAGE__->mk_classdata( "_cache_backends" );
17 __PACKAGE__->mk_accessors( "_default_curried_cache" );
22 # set it once per app, not once per plugin,
23 # and don't overwrite if some plugin was wicked
24 $app->_cache_backends({}) unless $app->_cache_backends;
26 my $ret = $app->NEXT::setup( @_ );
28 $app->setup_cache_backends;
33 sub get_default_cache_backend_config {
34 my ( $app, $name ) = @_;
35 $app->config->{cache}{backend} || $app->get_cache_backend_config("default");
38 sub get_cache_backend_config {
39 my ( $app, $name ) = @_;
40 $app->config->{cache}{backends}{$name};
43 sub setup_cache_backends {
46 # give plugins a chance to find things for themselves
47 $app->NEXT::setup_cache_backends;
49 foreach my $name ( keys %{ $app->config->{cache}{backends} } ) {
50 next if $app->get_cache_backend( $name );
51 $app->setup_generic_cache_backend( $name, $app->get_cache_backend_config( $name ) || {} );
54 if ( !$app->get_cache_backend("default") ) {
56 eval { $app->setup_generic_cache_backend( default => $app->get_default_cache_backend_config || {} ) };
60 sub default_cache_store {
62 $app->config->{cache}{default_store} || $app->guess_default_cache_store;
65 sub guess_default_cache_store {
68 my @stores = map { /Cache::Store::(.*)$/ ? $1 : () } $app->registered_plugins;
73 Carp::croak "You must configure a default store type unless you use exactly one store plugin.";
77 sub setup_generic_cache_backend {
78 my ( $app, $name, $config ) = @_;
79 my %config = %$config;
81 if ( my $class = delete $config{class} ) {
82 $app->setup_cache_backend_by_class( $name, $class, %config );
83 } elsif ( my $store = delete $config->{store} || $app->default_cache_store ) {
84 my $method = lc("setup_${store}_cache_backend");
86 Carp::croak "You must load the $store cache store plugin (if it exists). ".
87 "Please consult the Catalyst::Plugin::Cache documentation on how to configure hetrogeneous stores."
88 unless $app->can($method);
90 $app->$method( $name, %config );
92 $app->log->warn("Couldn't setup the cache backend named '$name'");
96 sub setup_cache_backend_by_class {
97 my ( $app, $name, $class, @args ) = @_;
98 Catalyst::Utils::ensure_class_loaded( $class );
99 $app->register_cache_backend( $name => $class->new( @args ) );
102 # end of spaghetti setup DWIM
105 my ( $c, @meta ) = @_;
109 return ( $c->get_preset_curried($name) || $c->get_cache_backend($name) );
111 # be nice and always return the same one for the simplest case
112 return ( $c->_default_curried_cache || $c->_default_curried_cache( $c->curry_cache( @meta ) ) );
114 return $c->curry_cache( @meta );
118 sub construct_curried_cache {
119 my ( $c, @meta ) = @_;
120 return $c->curried_cache_class( @meta )->new( @meta );
123 sub curried_cache_class {
124 my ( $c, @meta ) = @_;
125 $c->config->{cache}{curried_class} || "Catalyst::Plugin::Cache::Curried";
129 my ( $c, @meta ) = @_;
130 return $c->construct_curried_cache( $c, $c->_cache_caller_meta, @meta );
133 sub get_preset_curried {
134 my ( $c, $name ) = @_;
136 if ( ref( my $preset = $c->config->{cache}{profiles}{$name} ) ) {
137 return $preset if Scalar::Util::blessed($preset);
139 my @meta = ( ( ref $preset eq "HASH" ) ? %$preset : @$preset );
140 return $c->curry_cache( @meta );
146 sub get_cache_backend {
147 my ( $c, $name ) = @_;
148 $c->_cache_backends->{$name};
151 sub register_cache_backend {
152 my ( $c, $name, $backend ) = @_;
154 no warnings 'uninitialized';
155 Carp::croak("$backend does not look like a cache backend - "
156 . "it must be an object supporting get, set and remove")
157 unless eval { $backend->can("get") && $backend->can("set") && $backend->can("remove") };
159 $c->_cache_backends->{$name} = $backend;
162 sub unregister_cache_backend {
163 my ( $c, $name ) = @_;
164 delete $c->_cache_backends->{$name};
167 sub default_cache_backend {
169 $c->get_cache_backend( "default" ) || $c->temporary_cache_backend;
172 sub temporary_cache_backend {
174 die "FIXME - make up an in memory cache backend, that hopefully works well for the current engine";
177 sub _cache_caller_meta {
180 my ( $caller, $component, $controller );
182 for my $i ( 0 .. 15 ) { # don't look to far
183 my @info = caller(2 + $i) or last;
185 $caller ||= \@info unless $info[0] =~ /Plugin::Cache/;
186 $component ||= \@info if $info[0]->isa("Catalyst::Component");
187 $controller ||= \@info if $info[0]->isa("Catalyst::Controller");
189 last if $caller && $component && $controller;
192 my ( $caller_pkg, $component_pkg, $controller_pkg ) =
193 map { $_ ? $_->[0] : undef } $caller, $component, $controller;
196 'caller' => $caller_pkg,
197 component => $component_pkg,
198 controller => $controller_pkg,
199 caller_frame => $caller,
200 component_frame => $component,
201 controller_frame => $controller,
205 # this gets a shit name so that the plugins can override a good name
206 sub choose_cache_backend_wrapper {
207 my ( $c, @meta ) = @_;
209 Carp::croak("meta data must be an even sized list") unless @meta % 2 == 0;
213 unless ( exists $meta{'caller'} ) {
214 my %caller = $c->_cache_caller_meta;
215 @meta{keys %caller} = values %caller;
218 # allow the cache client to specify who it wants to cache with (but loeave room for a hook)
219 if ( exists $meta{backend} ) {
220 if ( Scalar::Util::blessed($meta{backend}) ) {
221 return $meta{backend};
223 return $c->get_cache_backend( $meta{backend} ) || $c->default_cache_backend;
227 if ( my $chosen = $c->choose_cache_backend( %meta ) ) {
228 $chosen = $c->get_cache_backend( $chosen ) unless Scalar::Util::blessed($chosen); # if it's a name find it
229 return $chosen if Scalar::Util::blessed($chosen); # only return if it was an object or name lookup worked
232 # die "no such backend"?
233 # currently, we fall back to default
236 return $c->default_cache_backend;
239 sub choose_cache_backend { shift->NEXT::choose_cache_backend( @_ ) } # a convenient fallback
242 my ( $c, $key, $value, @meta ) = @_;
243 $c->choose_cache_backend_wrapper( key => $key, value => $value, @meta )->set( $key, $value );
247 my ( $c, $key, @meta ) = @_;
248 $c->choose_cache_backend_wrapper( key => $key, @meta )->get( $key );
252 my ( $c, $key, @meta ) = @_;
253 $c->choose_cache_backend_wrapper( key => $key, @meta )->remove( $key );
264 Catalyst::Plugin::Cache - Flexible caching support for Catalyst.
272 # configure a backend or use a store plugin
273 __PACKAGE__->config->{cache}{backend} = {
274 class => "Cache::Bounded",
278 # ... in a controller
281 my ( $self, $c, $id ) = @_;
283 my $cache = $c->cache;
287 unless ( $result = $cache->get( $id ) ) {
288 # ... calulate result ...
289 $c->cache->set( $id, $result );
295 This plugin allows you to use a very simple configuration API without losing
296 the possibility of flexibility when you need it later.
298 Amongst it's features are support for multiple backends, segmentation based on
299 component or controller, keyspace partitioning and so forth, in various sub
306 =item cache $profile_name
310 Return a curried object with meta data from $profile_name or as explicitly
313 If a profile by the name $profile_name doesn't exist but a backend object by
314 that name does exist, the backend will be returned instead, since the interface
315 for curried caches and backends is almost identical.
317 This method can also be called without arguments, in which case is treated as
318 though the %meta hash was empty.
320 See L</META DATA> for details.
322 =item curry_cache %meta
324 Return a L<Catalyst::Plugin::Cache::Curried> object, curried with %meta.
326 See L</META DATA> for details.
328 =item cache_set $key, $value, %meta
330 =item cache_get $key, %meta
332 =item cache_remove $key, %meta
334 These cache operations will call L<choose_cache_backend> with %meta, and then
335 call C<set>, C<get> or C<remove> on the resulting backend object.
337 =item choose_cache_backend %meta
339 Select a backend object. This should return undef if no specific backend was
340 selected - it's caller will handle getting C<default_cache_backend> on it's own.
342 This method is typically used by plugins.
344 =item get_cache_backend $name
346 Get a backend object by name.
348 =item default_cache_backend
350 Return the default backend object.
352 =item temporary_cache_backend
354 When no default cache backend is configured this method might return a backend
355 known to work well with the current L<Catalyst::Engine>. This is a stup.
365 Whenever you set or retrieve a key you may specify additional meta data that
366 will be used to select a specific backend.
368 This metadata is very freeform, and the only key that has any meaning by
369 default is the C<backend> key which can be used to explicitly choose a backend
372 The C<choose_cache_backend> method can be overridden in order to facilitate
373 more intelligent backend selection. For example,
374 L<Catalyst::Plugin::Cache::Choose::KeyRegexes> overrides that method to select
375 a backend based on key regexes.
377 Another example is a L<Catalyst::Plugin::Cache::ControllerNamespacing>, which
378 that wraps backends in objects that perform key mangling, in order to keep
379 caches namespaced per controller.
381 However, this is generally left as a hook for larger, more complex
382 applications. Most configurations should make due
384 The simplest way to dynamically select a backend is based on the L</Cache
385 Profiles> configuratrion.
387 =head2 Meta Data Keys
389 C<choose_cache_backend> is called with some default keys.
395 Supplied by C<cache_get>, C<cache_set> and C<cache_remove>.
399 Supplied by C<cache_set>
403 The package name of the innermost caller that doesn't match
404 C<qr/Plugin::Cache/>.
408 The entire C<caller($i)> frame of C<caller>.
412 The package name of the innermost caller who C<isa> L<Catalyst::Component>.
414 =item component_frame
416 This entire C<caller($i)> frame of C<component>.
420 The package name of the innermost caller who C<isa> L<Catalyst::Controller>.
422 =item controller_frame
424 This entire C<caller($i)> frame of C<controller>.
428 =head2 Meta Data Currying
430 In order to avoid specifying %meta over and over again you may call C<cache> or
431 C<curry_cache> with %meta once, and get back a B<curried cache object>. This
432 object responds to the methods C<get>, C<set> and C<remove>, by appending it's
433 captured meta data and delegating them to C<cache_get>, C<cache_set> and
436 This is simpler than it sounds.
438 Here is an example using currying:
440 my $cache = $c->cache( %meta ); # cache is curried
442 $cache->set( $key, $value );
446 And here is an example without using currying:
448 $c->cache_set( $key, $value, %meta );
450 $c->cache_get( $key, %meta );
452 See L<Catalyst::Plugin::Cache::Curried> for details.
456 $c->config->{cache} = {
460 All configuration parameters should be provided in a hash reference under the
461 C<cache> key in the C<config> hash.
463 =head2 Backend Configuration
465 Configuring backend objects is done by adding hash entries under the
466 C<backends> keys in the main config.
468 A special case is that the hash key under the C<backend> (singular) key of the
469 main config is assumed to be the backend named C<default>.
475 Instantiate a backend from a L<Cache> compatible class. E.g.
477 $c->config->{cache}{backends}{small_things} = {
478 class => "Cache::Bounded",
483 $c->config->{cache}{backends}{large_things} = {
484 class => "Cache::Memcached::Mangaed",
485 data => '1.2.3.4:1234',
488 The options in the hash are passed to the class's C<new> method.
490 The class will be C<required> as necessary during setup time.
494 Instrantiate a backend using a store plugin, e.g.
496 $c->config->{cache}{backend} = {
500 Store plugins typically require less configuration because they are specialized
501 for L<Catalyst> applications. For example
502 L<Catalyst::Plugin::Cache::Store::FastMmap> will specify a default
503 C<share_file>, and additionally use a subclass of L<Cache::FastMmap> that can
504 also store non reference data.
506 The store plugin must be loaded.
510 =head2 Cache Profiles
516 Supply your own predefined profiles for cache metadata, when using the C<cache>
519 For example when you specify
521 $c->config->{cache}{profiles}{thumbnails} = {
522 backend => "large_things",
525 And then get a cache object like this:
527 $c->cache("thumbnails");
529 It is the same as if you had done:
531 $c->cache( backend => "large_things" );
535 =head2 Misc Configuration
541 When you do not specify a C<store> parameter in the backend configuration this
542 one will be used instead. This configuration parameter is not necessary if only
543 one store plugin is loaded.
553 An object that responds to the methods detailed in
554 L<Catalyst::Plugin::Cache::Backend> (or more).
558 A plugin that provides backends of a certain type. This is a bit like a factory.
562 Stored key/value pairs of data for easy re-access.
566 "extra" information about the item being stored, which can be used to locate an
571 my $cache = $c->cache(type => 'thumbnails');
572 $cache->set('pic01', $thumbnaildata);
574 A cache which has been pre-configured with a particular set of namespacing
575 data. In the example the cache returned could be one specifically tuned
576 for storing thumbnails.
578 An object that responds to C<get>, C<set> and C<remove>, and will automatically
579 add meta data to calls to C<< $c->cache_get >>, etc.