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