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