X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?p=catagits%2FCatalyst-Runtime.git;a=blobdiff_plain;f=lib%2FCatalyst.pm;h=e30d38ee06a11661126d387ada8f5020350d7a84;hp=b60196207d6739bb3382abed49ff634195d362f8;hb=8f6cebb2303a0b0eda9422430f926c3f83c72aed;hpb=829b22f766b0b1d1a09a6ce152abe48ad9bde5ec diff --git a/lib/Catalyst.pm b/lib/Catalyst.pm index b601962..e30d38e 100644 --- a/lib/Catalyst.pm +++ b/lib/Catalyst.pm @@ -27,6 +27,7 @@ use URI::https; use Tree::Simple qw/use_weak_refs/; use Tree::Simple::Visitor::FindByUID; use Class::C3::Adopt::NEXT; +use List::MoreUtils qw/uniq/; use attributes; use utf8; use Carp qw/croak carp shortmess/; @@ -1206,6 +1207,12 @@ path, use C<< $c->uri_for_action >> instead. sub uri_for { my ( $c, $path, @args ) = @_; + if (blessed($path) && $path->isa('Catalyst::Controller')) { + $path = $path->path_prefix; + $path =~ s{/+\z}{}; + $path .= '/'; + } + if ( blessed($path) ) { # action object my $captures = ( scalar @args && ref $args[0] eq 'ARRAY' ? shift(@args) @@ -2126,40 +2133,31 @@ sub setup_actions { my $c = shift; $c->dispatcher->setup_actions( $c, @_ ) } =head2 $c->setup_components -Sets up components. Specify a C config option to pass -additional options directly to L. To add additional -search paths, specify a key named C as an array -reference. Items in the array beginning with C<::> will have the -application class name prepended to them. +This method is called internally to set up the application's components. + +It finds modules by calling the L method, expands them to +package names with the L method, and then installs +each component into the application. + +The C config option is passed to both of the above methods. -All components found will also have any -L loaded and set up as components. -Note, that modules which are B an I of the main -file namespace loaded will not be instantiated as components. +Installation of each component is performed by the L method, +below. =cut sub setup_components { my $class = shift; - my @paths = qw( ::Controller ::C ::Model ::M ::View ::V ); my $config = $class->config->{ setup_components }; - my $extra = delete $config->{ search_extra } || []; - - push @paths, @$extra; - - my $locator = Module::Pluggable::Object->new( - search_path => [ map { s/^(?=::)/$class/; $_; } @paths ], - %$config - ); - my @comps = sort { length $a <=> length $b } $locator->plugins; - my %comps = map { $_ => 1 } @comps; + my @comps = sort { length $a <=> length $b } + $class->locate_components($config); - my $deprecated_component_names = grep { /::[CMV]::/ } @comps; + my $deprecatedcatalyst_component_names = grep { /::[CMV]::/ } @comps; $class->log->warn(qq{Your application is using the deprecated ::[MVC]:: type naming scheme.\n}. qq{Please switch your class names to ::Model::, ::View:: and ::Controller: as appropriate.\n} - ) if $deprecated_component_names; + ) if $deprecatedcatalyst_component_names; for my $component ( @comps ) { @@ -2168,30 +2166,76 @@ sub setup_components { # we know M::P::O found a file on disk so this is safe Catalyst::Utils::ensure_class_loaded( $component, { ignore_loaded => 1 } ); - #Class::MOP::load_class($component); - - my $module = $class->setup_component( $component ); - my %modules = ( - $component => $module, - map { - $_ => $class->setup_component( $_ ) - } grep { - not exists $comps{$_} - } Devel::InnerPackage::list_packages( $component ) - ); - for my $key ( keys %modules ) { - $class->components->{ $key } = $modules{ $key }; - } + # Needs to be done as soon as the component is loaded, as loading a sub-component + # (next time round the loop) can cause us to get the wrong metaclass.. + $class->_controller_init_base_classes($component); } + + for my $component (uniq map { $class->expand_component_module( $_, $config ) } @comps ) { + $class->_controller_init_base_classes($component); # Also cover inner packages + $class->components->{ $component } = $class->setup_component($component); + } +} + +=head2 $c->locate_components( $setup_component_config ) + +This method is meant to provide a list of component modules that should be +setup for the application. By default, it will use L. + +Specify a C config option to pass additional options directly +to L. To add additional search paths, specify a key named +C as an array reference. Items in the array beginning with C<::> +will have the application class name prepended to them. + +=cut + +sub locate_components { + my $class = shift; + my $config = shift; + + my @paths = qw( ::Controller ::C ::Model ::M ::View ::V ); + my $extra = delete $config->{ search_extra } || []; + + push @paths, @$extra; + + my $locator = Module::Pluggable::Object->new( + search_path => [ map { s/^(?=::)/$class/; $_; } @paths ], + %$config + ); + + my @comps = $locator->plugins; + + return @comps; +} + +=head2 $c->expand_component_module( $component, $setup_component_config ) + +Components found by C will be passed to this method, which +is expected to return a list of component (package) names to be set up. + +By default, this method will return the component itself as well as any inner +packages found by L. + +=cut + +sub expand_component_module { + my ($class, $module) = @_; + my @inner = Devel::InnerPackage::list_packages( $module ); + return ($module, @inner); } =head2 $c->setup_component =cut +# FIXME - Ugly, ugly hack to ensure the we force initialize non-moose base classes +# nearest to Catalyst::Controller first, no matter what order stuff happens +# to be loaded. There are TODO tests in Moose for this, see +# f2391d17574eff81d911b97be15ea51080500003 sub _controller_init_base_classes { my ($app_class, $component) = @_; + return unless $component->isa('Catalyst::Controller'); foreach my $class ( reverse @{ mro::get_linear_isa($component) } ) { Moose::Meta::Class->initialize( $class ) unless find_meta($class); @@ -2205,20 +2249,13 @@ sub setup_component { return $component; } - # FIXME - Ugly, ugly hack to ensure the we force initialize non-moose base classes - # nearest to Catalyst::Controller first, no matter what order stuff happens - # to be loaded. There are TODO tests in Moose for this, see - # f2391d17574eff81d911b97be15ea51080500003 - if ($component->isa('Catalyst::Controller')) { - $class->_controller_init_base_classes($component); - } - my $suffix = Catalyst::Utils::class2classsuffix( $component ); my $config = $class->config->{ $suffix } || {}; - $config->{_component_name} = $component; # Put this in args here, rather - # than in COMPONENT as there - # are lots of custom COMPONENT - # methods.. + # Stash catalyst_component_name in the config here, so that custom COMPONENT + # methods also pass it. local to avoid pointlessly shitting in config + # for the debug screen, as $component is already the key name. + local $config->{catalyst_component_name} = $component; + my $instance = eval { $component->COMPONENT( $class, $config ); }; if ( my $error = $@ ) { @@ -2637,6 +2674,18 @@ changes are made to the request. The host value for $c->req->base and $c->req->uri is set to the real host, as read from the HTTP X-Forwarded-Host header. +Additionally, you may be running your backend application on an insecure +connection (port 80) while your frontend proxy is running under SSL. If there +is a discrepancy in the ports, use the HTTP header C to +tell Catalyst what port the frontend listens on. This will allow all URIs to +be created properly. + +In the case of passing in: + + X-Forwarded-Port: 443 + +All calls to C will result in an https link, as is expected. + Obviously, your web server must support these headers for this to work. In a more complex server farm environment where you may have your