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