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