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