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