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