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