e5609b303efc1846df5a3056d227373ca72f6742
[catagits/Catalyst-Runtime.git] / lib / Catalyst / IOC / Container.pm
1 package Catalyst::IOC::Container;
2 use Bread::Board;
3 use Moose;
4 use Config::Any;
5 use Data::Visitor::Callback;
6 use Catalyst::Utils ();
7 use List::Util qw(first);
8 use Devel::InnerPackage ();
9 use Hash::Util qw/lock_hash/;
10 use MooseX::Types::LoadableClass qw/ LoadableClass /;
11 use Moose::Util;
12 use Scalar::Util qw/refaddr/;
13 use Catalyst::IOC::BlockInjection;
14 use Catalyst::IOC::ConstructorInjection;
15 use Module::Pluggable::Object ();
16 use namespace::autoclean;
17
18 extends 'Bread::Board::Container';
19
20 has config_local_suffix => (
21     is      => 'ro',
22     isa     => 'Str',
23     default => 'local',
24 );
25
26 has driver => (
27     is      => 'ro',
28     isa     => 'HashRef',
29     default => sub { +{} },
30 );
31
32 has file => (
33     is      => 'ro',
34     isa     => 'Str',
35     default => '',
36 );
37
38 has substitutions => (
39     is      => 'ro',
40     isa     => 'HashRef',
41     default => sub { +{} },
42 );
43
44 has application => (
45     is       => 'ro',
46     isa      => 'Catalyst|Str',
47     lazy     => 1,
48     default  => sub { shift->application_name },
49 );
50
51 has application_name => (
52     is       => 'ro',
53     isa      => 'Str',
54     required => 1,
55 );
56
57 has sub_container_class => (
58     isa     => LoadableClass,
59     is      => 'ro',
60     coerce  => 1,
61     default => 'Catalyst::IOC::SubContainer',
62     handles => {
63         new_sub_container => 'new',
64     }
65 );
66
67 sub BUILD {
68     my ( $self, $params ) = @_;
69
70     $self->add_service(
71         $self->${\"build_${_}_service"}
72     ) for qw/
73         substitutions
74         file
75         driver
76         application
77         application_name
78         prefix
79         extensions
80         path
81         config
82         raw_config
83         global_files
84         local_files
85         global_config
86         local_config
87         class_config
88         config_local_suffix
89         config_path
90         locate_components
91     /;
92
93     my $config = $self->resolve( service => 'config' );
94
95     # don't force default_component to be undef if the config wasn't set
96     my @default_view  = $config->{default_view}
97                       ? ( default_component => $config->{default_view} )
98                       : ( )
99                       ;
100     my @default_model = $config->{default_model}
101                       ? ( default_component => $config->{default_model} )
102                       : ( )
103                       ;
104
105     $self->add_sub_container(
106         $self->build_component_subcontainer
107     );
108
109     $self->add_sub_container(
110         $self->build_controller_subcontainer
111     );
112
113     $self->add_sub_container(
114         $self->build_view_subcontainer( @default_view )
115     );
116
117     $self->add_sub_container(
118         $self->build_model_subcontainer( @default_model )
119     );
120
121     {
122         no strict 'refs';
123         no warnings 'once';
124         my $class = ref $self;
125         ${ $class . '::customise_container' }->($self)
126             if ${ $class . '::customise_container' };
127     }
128 }
129
130 sub build_model_subcontainer {
131     my $self = shift;
132
133     return $self->new_sub_container( @_,
134         name => 'model',
135     );
136 }
137
138 sub build_view_subcontainer {
139     my $self = shift;
140
141     return $self->new_sub_container( @_,
142         name => 'view',
143     );
144 }
145
146 sub build_controller_subcontainer {
147     my $self = shift;
148
149     return $self->new_sub_container(
150         name => 'controller',
151     );
152 }
153
154 sub build_component_subcontainer {
155     my $self = shift;
156
157     return Bread::Board::Container->new(
158         name => 'component',
159     );
160 }
161
162 sub build_home_service {
163     my $self = shift;
164
165     return Bread::Board::BlockInjection->new(
166         lifecycle => 'Singleton',
167         name => 'home',
168         block => sub {
169             my $self = shift;
170             my $class = $self->param('application_name');
171             my $home;
172
173             if ( my $env = Catalyst::Utils::env_value( $class, 'HOME' ) ) {
174                 $home = $env;
175             }
176
177             $home ||= Catalyst::Utils::home($class);
178             return $home;
179         },
180         dependencies => [ depends_on('application_name') ],
181     );
182 }
183
184 # FIXME: very ambiguous - maybe root_dir?
185 sub build_root_service {
186     my $self = shift;
187
188     return Bread::Board::BlockInjection->new(
189         lifecycle => 'Singleton',
190         name => 'root',
191         block => sub {
192             my $self = shift;
193
194             return Path::Class::Dir->new( $self->param('home') )->subdir('root');
195         },
196         dependencies => [ depends_on('home') ],
197     );
198 }
199
200 sub build_application_service {
201     my $self = shift;
202
203     return Bread::Board::Literal->new(
204         name  => 'application',
205         value => $self->application,
206     );
207 }
208
209 sub build_application_name_service {
210     my $self = shift;
211
212     return Bread::Board::Literal->new( name => 'application_name', value => $self->application_name );
213 }
214
215 sub build_driver_service {
216     my $self = shift;
217
218     return Bread::Board::Literal->new( name => 'driver', value => $self->driver );
219 }
220
221 sub build_file_service {
222     my $self = shift;
223
224     return Bread::Board::Literal->new( name => 'file', value => $self->file );
225 }
226
227 sub build_substitutions_service {
228     my $self = shift;
229
230     return Bread::Board::Literal->new( name => 'substitutions', value => $self->substitutions );
231 }
232
233 sub build_extensions_service {
234     my $self = shift;
235
236     return Bread::Board::BlockInjection->new(
237         lifecycle => 'Singleton',
238         name => 'extensions',
239         block => sub {
240             return \@{Config::Any->extensions};
241         },
242     );
243 }
244
245 sub build_prefix_service {
246     my $self = shift;
247
248     return Bread::Board::BlockInjection->new(
249         lifecycle => 'Singleton',
250         name => 'prefix',
251         block => sub {
252             return Catalyst::Utils::appprefix( shift->param('application_name') );
253         },
254         dependencies => [ depends_on('application_name') ],
255     );
256 }
257
258 sub build_path_service {
259     my $self = shift;
260
261     return Bread::Board::BlockInjection->new(
262         lifecycle => 'Singleton',
263         name => 'path',
264         block => sub {
265             my $s = shift;
266
267             return Catalyst::Utils::env_value( $s->param('application_name'), 'CONFIG' )
268             || $s->param('file')
269             || $s->param('application_name')->path_to( $s->param('prefix') );
270         },
271         dependencies => [ depends_on('file'), depends_on('application_name'), depends_on('prefix') ],
272     );
273 }
274
275 sub build_config_service {
276     my $self = shift;
277
278     return Bread::Board::BlockInjection->new(
279         lifecycle => 'Singleton',
280         name => 'config',
281         block => sub {
282             my $s = shift;
283
284             my $v = Data::Visitor::Callback->new(
285                 plain_value => sub {
286                     return unless defined $_;
287                     return $self->_config_substitutions( $s->param('application_name'), $s->param('substitutions'), $_ );
288                 }
289
290             );
291             $v->visit( $s->param('raw_config') );
292         },
293         dependencies => [ depends_on('application_name'), depends_on('raw_config'), depends_on('substitutions') ],
294     );
295 }
296
297 sub build_raw_config_service {
298     my $self = shift;
299
300     return Bread::Board::BlockInjection->new(
301         lifecycle => 'Singleton',
302         name => 'raw_config',
303         block => sub {
304             my $s = shift;
305
306             my @global = @{$s->param('global_config')};
307             my @locals = @{$s->param('local_config')};
308
309             my $config = $s->param('class_config');
310
311             for my $cfg (@global, @locals) {
312                 for (keys %$cfg) {
313                     $config = Catalyst::Utils::merge_hashes( $config, $cfg->{$_} );
314                 }
315             }
316
317             return $config;
318         },
319         dependencies => [ depends_on('global_config'), depends_on('local_config'), depends_on('class_config') ],
320     );
321 }
322
323 sub build_global_files_service {
324     my $self = shift;
325
326     return Bread::Board::BlockInjection->new(
327         lifecycle => 'Singleton',
328         name => 'global_files',
329         block => sub {
330             my $s = shift;
331
332             my ( $path, $extension ) = @{$s->param('config_path')};
333
334             my @extensions = @{$s->param('extensions')};
335
336             my @files;
337             if ( $extension ) {
338                 die "Unable to handle files with the extension '${extension}'" unless grep { $_ eq $extension } @extensions;
339                 push @files, $path;
340             } else {
341                 @files = map { "$path.$_" } @extensions;
342             }
343             return \@files;
344         },
345         dependencies => [ depends_on('extensions'), depends_on('config_path') ],
346     );
347 }
348
349 sub build_local_files_service {
350     my $self = shift;
351
352     return Bread::Board::BlockInjection->new(
353         lifecycle => 'Singleton',
354         name => 'local_files',
355         block => sub {
356             my $s = shift;
357
358             my ( $path, $extension ) = @{$s->param('config_path')};
359             my $suffix = $s->param('config_local_suffix');
360
361             my @extensions = @{$s->param('extensions')};
362
363             my @files;
364             if ( $extension ) {
365                 die "Unable to handle files with the extension '${extension}'" unless grep { $_ eq $extension } @extensions;
366                 $path =~ s{\.$extension}{_$suffix.$extension};
367                 push @files, $path;
368             } else {
369                 @files = map { "${path}_${suffix}.$_" } @extensions;
370             }
371             return \@files;
372         },
373         dependencies => [ depends_on('extensions'), depends_on('config_path'), depends_on('config_local_suffix') ],
374     );
375 }
376
377 sub build_class_config_service {
378     my $self = shift;
379
380     return Bread::Board::BlockInjection->new(
381         lifecycle => 'Singleton',
382         name => 'class_config',
383         block => sub {
384             my $s   = shift;
385             my $app = $s->param('application_name');
386
387             # Container might be called outside Catalyst context
388             return {} unless Class::MOP::is_class_loaded($app);
389
390             # config might not have been defined
391             return $app->config || {};
392         },
393         dependencies => [ depends_on('application_name') ],
394     );
395 }
396
397 sub build_global_config_service {
398     my $self = shift;
399
400     return Bread::Board::BlockInjection->new(
401         lifecycle => 'Singleton',
402         name => 'global_config',
403         block => sub {
404             my $s = shift;
405
406             return Config::Any->load_files({
407                 files       => $s->param('global_files'),
408                 filter      => \&_fix_syntax,
409                 use_ext     => 1,
410                 driver_args => $s->param('driver'),
411             });
412         },
413         dependencies => [ depends_on('global_files') ],
414     );
415 }
416
417 sub build_local_config_service {
418     my $self = shift;
419
420     return Bread::Board::BlockInjection->new(
421         lifecycle => 'Singleton',
422         name => 'local_config',
423         block => sub {
424             my $s = shift;
425
426             return Config::Any->load_files({
427                 files       => $s->param('local_files'),
428                 filter      => \&_fix_syntax,
429                 use_ext     => 1,
430                 driver_args => $s->param('driver'),
431             });
432         },
433         dependencies => [ depends_on('local_files') ],
434     );
435 }
436
437 sub build_config_path_service {
438     my $self = shift;
439
440     return Bread::Board::BlockInjection->new(
441         lifecycle => 'Singleton',
442         name => 'config_path',
443         block => sub {
444             my $s = shift;
445
446             my $path = $s->param('path');
447             my $prefix = $s->param('prefix');
448
449             my ( $extension ) = ( $path =~ m{\.(.{1,4})$} );
450
451             if ( -d $path ) {
452                 $path =~ s{[\/\\]$}{};
453                 $path .= "/$prefix";
454             }
455
456             return [ $path, $extension ];
457         },
458         dependencies => [ depends_on('prefix'), depends_on('path') ],
459     );
460 }
461
462 sub build_config_local_suffix_service {
463     my $self = shift;
464
465     return Bread::Board::BlockInjection->new(
466         lifecycle => 'Singleton',
467         name => 'config_local_suffix',
468         block => sub {
469             my $s = shift;
470             my $suffix = Catalyst::Utils::env_value( $s->param('application_name'), 'CONFIG_LOCAL_SUFFIX' ) || $self->config_local_suffix;
471
472             return $suffix;
473         },
474         dependencies => [ depends_on('application_name') ],
475     );
476 }
477
478 sub build_locate_components_service {
479     my $self = shift;
480
481     return Bread::Board::BlockInjection->new(
482         lifecycle => 'Singleton',
483         name      => 'locate_components',
484         block     => sub {
485             my $s      = shift;
486             my $class  = $s->param('application_name');
487             my $config = $s->param('config')->{ setup_components };
488
489             Catalyst::Exception->throw(
490                 qq{You are using search_extra config option. That option is\n} .
491                 qq{deprecated, please refer to the documentation for\n} .
492                 qq{other ways of achieving the same results.\n}
493             ) if delete $config->{ search_extra };
494
495             my @paths = qw( ::Controller ::C ::Model ::M ::View ::V );
496
497             my $locator = Module::Pluggable::Object->new(
498                 search_path => [ map { s/^(?=::)/$class/; $_; } @paths ],
499                 %$config
500             );
501
502             return [ $locator->plugins ];
503         },
504         dependencies => [ depends_on('application_name'), depends_on('config') ],
505     );
506 }
507
508 sub setup_components {
509     my $self = shift;
510     my $class = $self->resolve( service => 'application_name' );
511     my @comps = @{ $self->resolve( service => 'locate_components' ) };
512     my %comps = map { $_ => 1 } @comps;
513     my $deprecatedcatalyst_component_names = 0;
514
515     my $app_locate_components_addr = refaddr(
516         $class->can('locate_components')
517     );
518     my $cat_locate_components_addr = refaddr(
519         Catalyst->can('locate_components')
520     );
521
522     if ($app_locate_components_addr != $cat_locate_components_addr) {
523         # FIXME - why not just say: @comps = $class->locate_components() ?
524         $class->log->warn(qq{You have overridden locate_components. That } .
525             qq{no longer works. Please refer to the documentation to achieve } .
526             qq{similar results.\n}
527         );
528     }
529
530     for my $component ( @comps ) {
531
532         # We pass ignore_loaded here so that overlay files for (e.g.)
533         # Model::DBI::Schema sub-classes are loaded - if it's in @comps
534         # we know M::P::O found a file on disk so this is safe
535
536         Catalyst::Utils::ensure_class_loaded( $component, { ignore_loaded => 1 } );
537     }
538
539     for my $component (@comps) {
540         $self->add_component( $component );
541         # FIXME - $instance->expand_modules() is broken
542         my @expanded_components = $self->expand_component_module( $component );
543
544         if (
545             !$deprecatedcatalyst_component_names &&
546             ($deprecatedcatalyst_component_names = $component =~ m/::[CMV]::/) ||
547             ($deprecatedcatalyst_component_names = grep { /::[CMV]::/ } @expanded_components)
548         ) {
549             # FIXME - should I be calling warn here?
550             # Maybe it's time to remove it, or become fatal
551             $class->log->warn(qq{Your application is using the deprecated ::[MVC]:: type naming scheme.\n}.
552                 qq{Please switch your class names to ::Model::, ::View:: and ::Controller: as appropriate.\n}
553             );
554         }
555
556         for my $component (@expanded_components) {
557             $self->add_component( $component )
558                 unless $comps{$component};
559         }
560     }
561 }
562
563 sub _fix_syntax {
564     my $config     = shift;
565     my @components = (
566         map +{
567             prefix => $_ eq 'Component' ? '' : $_ . '::',
568             values => delete $config->{ lc $_ } || delete $config->{ $_ }
569         },
570         grep { ref $config->{ lc $_ } || ref $config->{ $_ } }
571             qw( Component Model M View V Controller C Plugin )
572     );
573
574     foreach my $comp ( @components ) {
575         my $prefix = $comp->{ prefix };
576         foreach my $element ( keys %{ $comp->{ values } } ) {
577             $config->{ "$prefix$element" } = $comp->{ values }->{ $element };
578         }
579     }
580 }
581
582 sub _config_substitutions {
583     my ( $self, $name, $subs, $arg ) = @_;
584
585     $subs->{ HOME } ||= sub { shift->path_to( '' ); };
586     $subs->{ ENV } ||=
587         sub {
588             my ( $c, $v ) = @_;
589             if (! defined($ENV{$v})) {
590                 Catalyst::Exception->throw( message =>
591                     "Missing environment variable: $v" );
592                 return "";
593             } else {
594                 return $ENV{ $v };
595             }
596         };
597     $subs->{ path_to } ||= sub { shift->path_to( @_ ); };
598     $subs->{ literal } ||= sub { return $_[ 1 ]; };
599     my $subsre = join( '|', keys %$subs );
600
601     $arg =~ s{__($subsre)(?:\((.+?)\))?__}{ $subs->{ $1 }->( $name, $2 ? split( /,/, $2 ) : () ) }eg;
602     return $arg;
603 }
604
605 sub get_component_from_sub_container {
606     my ( $self, $sub_container_name, $name, $c, @args ) = @_;
607
608     my $sub_container = $self->get_sub_container( $sub_container_name );
609
610     if (!$name) {
611         my $default = $sub_container->default_component;
612
613         return $sub_container->get_component( $default, $c, @args )
614             if $default && $sub_container->has_service( $default );
615
616         # FIXME - should I be calling $c->log->warn here?
617         # this is never a controller, so this is safe
618         $c->log->warn( "Calling \$c->$sub_container_name() is not supported unless you specify one of:" );
619         $c->log->warn( "* \$c->config(default_$sub_container_name => 'the name of the default $sub_container_name to use')" );
620         $c->log->warn( "* \$c->stash->{current_$sub_container_name} # the name of the view to use for this request" );
621         $c->log->warn( "* \$c->stash->{current_${sub_container_name}_instance} # the instance of the $sub_container_name to use for this request" );
622
623         return;
624     }
625
626     return $sub_container->get_component_regexp( $name, $c, @args )
627         if ref $name;
628
629     return $sub_container->get_component( $name, $c, @args )
630         if $sub_container->has_service( $name );
631
632     $c->log->warn(
633         "Attempted to use $sub_container_name '$name', " .
634         "but it does not exist"
635     );
636
637     return;
638 }
639
640 sub find_component {
641     my ( $self, $component, @args ) = @_;
642     my ( $type, $name ) = _get_component_type_name($component);
643     my @result;
644
645     return $self->get_component_from_sub_container(
646         $type, $name, @args
647     ) if $type;
648
649     my $query = ref $component
650               ? $component
651               : qr{^$component$}
652               ;
653
654     for my $subcontainer_name (qw/model view controller/) {
655         my $subcontainer = $self->get_sub_container( $subcontainer_name );
656         my @components   = $subcontainer->get_service_list;
657         @result          = grep { m{$component} } @components;
658
659         return map { $subcontainer->get_component( $_, @args ) } @result
660             if @result;
661     }
662
663     # one last search for things like $c->comp(qr/::M::/)
664     @result = $self->_find_component_regexp(
665         $component, @args
666     ) if !@result and ref $component;
667
668     # it expects an empty list on failed searches
669     return @result;
670 }
671
672 sub _find_component_regexp {
673     my ( $self, $component, $ctx, @args ) = @_;
674     my @result;
675
676     my @components = grep { m{$component} } keys %{ $self->get_all_components($ctx) };
677
678     for (@components) {
679         my ($type, $name) = _get_component_type_name($_);
680
681         push @result, $self->get_component_from_sub_container(
682             $type, $name, $ctx, @args
683         ) if $type;
684     }
685
686     return @result;
687 }
688
689 sub get_all_components {
690     my ($self, $class) = @_;
691     my %components;
692
693     # FIXME - if we're getting from these containers, we need to either:
694     #   - pass 'ctx' and 'accept_context_args' OR
695     #   - make these params optional
696     # big problem when setting up the dispatcher - this method is called
697     # as $container->get_all_components('MyApp'). What to do with Request
698     # life cycles?
699     foreach my $type (qw/model view controller /) {
700         my $container = $self->get_sub_container($type);
701
702         for my $component ($container->get_service_list) {
703             my $comp_service = $container->get_service($component);
704
705             $components{$comp_service->catalyst_component_name} = $comp_service->get(ctx => $class);
706         }
707     }
708
709     return lock_hash %components;
710 }
711
712 sub add_component {
713     my ( $self, $component ) = @_;
714     my ( $type, $name ) = _get_component_type_name($component);
715
716     return unless $type;
717
718     # The 'component' sub-container will create the object, and store it's
719     # instance, which, by default, will live throughout the application.
720     # The model/view/controller sub-containers only reference the instance
721     # held in the aforementioned sub-container, and execute the ACCEPT_CONTEXT
722     # sub every time they are called, when it exists.
723     my $instance_container       = $self->get_sub_container('component');
724     my $accept_context_container = $self->get_sub_container($type);
725
726     # Custom containers might have added the service already
727     # We don't want to override that
728     return if $accept_context_container->has_service( $name );
729
730     my $component_service_name = "${type}_${name}";
731
732     $instance_container->add_service(
733         Catalyst::IOC::ConstructorInjection->new(
734             name      => $component_service_name,
735             catalyst_component_name => $component,
736             class     => $component,
737             lifecycle => 'Singleton',
738             dependencies => [
739                 depends_on( '/application' ),
740             ],
741         ),
742     );
743     # XXX - FIXME - We have to explicitly build the service here,
744     #               causing the COMPONENT method to be called early here, as otherwise
745     #               if the component method defines other classes (e.g. the
746     #               ACCEPT_CONTEXT injection Model::DBIC::Schema does)
747     #               then they won't be found by Devel::InnerPackage
748     # see also t/aggregate/unit_core_component_loading.t
749     $instance_container->get_service($component_service_name)->get;
750
751     $accept_context_container->add_service(
752         Catalyst::IOC::BlockInjection->new(
753             name         => $name,
754             catalyst_component_name => $component,
755             dependencies => [
756                 depends_on( "/component/$component_service_name" ),
757             ],
758             block => sub { shift->param($component_service_name) },
759         )
760     );
761 }
762
763 # FIXME: should this sub exist?
764 # should it be moved to Catalyst::Utils,
765 # or replaced by something already existing there?
766 sub _get_component_type_name {
767     my ( $component ) = @_;
768     my $result;
769
770     while ( !$result and (my $index = index $component, '::') > 0 ) {
771         my $type   = lc substr $component, 0, $index;
772         $component = substr $component, $index + 2;
773         $result    = first { $type eq $_ or $type eq substr($_, 0, 1) }
774                          qw{ model view controller };
775     }
776
777     return ($result, $component);
778 }
779
780 sub expand_component_module {
781     my ( $class, $module ) = @_;
782     return Devel::InnerPackage::list_packages( $module );
783 }
784
785 __PACKAGE__->meta->make_immutable;
786
787 1;
788
789 __END__
790
791 =pod
792
793 =head1 NAME
794
795 Catalyst::Container - IOC for Catalyst components
796
797 =head1 SYNOPSIS
798
799 =head1 DESCRIPTION
800
801 =head1 METHODS
802
803 =head1 Methods for Building Containers
804
805 =head2 build_component_subcontainer
806
807 Container that stores all components, i.e. all models, views and controllers
808 together. Each service is an instance of the actual component, and by default
809 it lives while the application is running. Retrieving components from this
810 sub-container will instantiate the component, if it hasn't been instantiated
811 already, but will not execute ACCEPT_CONTEXT.
812
813 =head2 build_model_subcontainer
814
815 Container that stores references for all models that are inside the components
816 sub-container. Retrieving a model triggers ACCEPT_CONTEXT, if it exists.
817
818 =head2 build_view_subcontainer
819
820 Same as L<build_model_subcontainer>, but for views.
821
822 =head2 build_controller_subcontainer
823
824 Same as L<build_model_subcontainer>, but for controllers.
825
826 =head1 Methods for Building Services
827
828 =head2 build_application_name_service
829
830 Name of the application (such as MyApp).
831
832 =head2 build_driver_service
833
834 Config options passed directly to the driver being used.
835
836 =head2 build_file_service
837
838 ?
839
840 =head2 build_substitutions_service
841
842 This method substitutes macros found with calls to a function. There are a
843 number of default macros:
844
845 =over
846
847 =item * C<__HOME__> - replaced with C<$c-E<gt>path_to('')>
848
849 =item * C<__ENV(foo)__> - replaced with the value of C<$ENV{foo}>
850
851 =item * C<__path_to(foo/bar)__> - replaced with C<$c-E<gt>path_to('foo/bar')>
852
853 =item * C<__literal(__FOO__)__> - leaves __FOO__ alone (allows you to use
854 C<__DATA__> as a config value, for example)
855
856 =back
857
858 The parameter list is split on comma (C<,>). You can override this method to
859 do your own string munging, or you can define your own macros in
860 C<< <MyApp->config( 'Plugin::ConfigLoader' => { substitutions => { ... } } ) >>.
861 Example:
862
863     MyApp->config( 'Plugin::ConfigLoader' => {
864         substitutions => {
865             baz => sub { my $c = shift; qux( @_ ); },
866         },
867     });
868
869 The above will respond to C<__baz(x,y)__> in config strings.
870
871 =head2 build_extensions_service
872
873 Config::Any's available config file extensions (e.g. xml, json, pl, etc).
874
875 =head2 build_prefix_service
876
877 The prefix, based on the application name, that will be used to look-up the
878 config files (which will be in the format $prefix.$extension). If the app is
879 MyApp::Foo, the prefix will be myapp_foo.
880
881 =head2 build_path_service
882
883 The path to the config file (or environment variable, if defined).
884
885 =head2 build_config_service
886
887 The resulting configuration for the application, after it has successfully
888 been loaded, and all substitutions have been made.
889
890 =head2 build_raw_config_service
891
892 The merge of local_config and global_config hashes, before substitutions.
893
894 =head2 build_global_files_service
895
896 Gets all files for config that don't have the local_suffix, such as myapp.conf.
897
898 =head2 build_local_files_service
899
900 Gets all files for config that have the local_suffix, such as myapp_local.conf.
901
902 =head2 build_global_config_service
903
904 Reads config from global_files.
905
906 =head2 build_local_config_service
907
908 Reads config from local_files.
909
910 =head2 build_class_config_service
911
912 Reads config set from the application's class attribute config,
913 i.e. MyApp->config( name => 'MyApp', ... )
914
915 =head2 build_config_path_service
916
917 Splits the path to the config file, and returns on array ref containing
918 the path to the config file minus the extension in the first position,
919 and the extension in the second.
920
921 =head2 build_config_local_suffix_service
922
923 Determines the suffix of files used to override the main config. By default
924 this value is C<local>, which will load C<myapp_local.conf>.  The suffix can
925 be specified in the following order of preference:
926
927 =over
928
929 =item * C<$ENV{ MYAPP_CONFIG_LOCAL_SUFFIX }>
930
931 =item * C<$ENV{ CATALYST_CONFIG_LOCAL_SUFFIX }>
932
933 =back
934
935 The first one of these values found replaces the default of C<local> in the
936 name of the local config file to be loaded.
937
938 For example, if C< $ENV{ MYAPP_CONFIG_LOCAL_SUFFIX }> is set to C<testing>,
939 ConfigLoader will try and load C<myapp_testing.conf> instead of
940 C<myapp_local.conf>.
941
942 =head2 build_locate_components_service
943
944 This method is meant to provide a list of component modules that should be
945 setup for the application.  By default, it will use L<Module::Pluggable>.
946
947 Specify a C<setup_components> config option to pass additional options directly
948 to L<Module::Pluggable>.
949
950 =head1 Other methods
951
952 =head2 get_component_from_sub_container($sub_container, $name, $c, @args)
953
954 Looks for components in a given sub-container (such as controller, model or
955 view), and returns the searched component. If $name is undef, it returns the
956 default component (such as default_view, if $sub_container is 'view'). If
957 $name is a regexp, it returns an array of matching components. Otherwise, it
958 looks for the component with name $name.
959
960 =head2 get_all_components
961
962 Fetches all the components, in each of the sub_containers model, view and
963 controller, and returns a read-only hash. The keys are the class names, and
964 the values are the blessed objects. This is what is returned by $c->components.
965
966 =head2 add_component
967
968 Adds a component to the appropriate sub-container. The sub-container is guessed
969 by the component name given.
970
971 =head2 find_component
972
973 Searches for components in all containers. If $component is the full class
974 name, the sub-container is guessed, and it gets the searched component in there.
975 Otherwise, it looks for a component with that name in all sub-containers. If
976 $component is a regexp it calls _find_component_regexp and matches all
977 components against that regexp.
978
979 =head2 expand_component_module
980
981 Components found by C<locate_components> will be passed to this method, which
982 is expected to return a list of component (package) names to be set up.
983
984 =head2 setup_components
985
986 Uses locate_components service to list the components, and adds them to the
987 appropriate sub-containers, using add_component().
988
989 =head1 AUTHORS
990
991 Catalyst Contributors, see Catalyst.pm
992
993 =head1 COPYRIGHT
994
995 This library is free software. You can redistribute it and/or modify it under
996 the same terms as Perl itself.
997
998 =cut