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