X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?p=catagits%2FCatalyst-Runtime.git;a=blobdiff_plain;f=lib%2FCatalyst.pm;h=17c9403bb3c4404339671a07ca064aaa790dd394;hp=81d2a942562f9080ffaad859e297f3ea514612cc;hb=81f25ce60d12146ada6baa3ed8db87a0e8a54408;hpb=4600a5a1d3ce6af857121e3482e5a22233a3b314 diff --git a/lib/Catalyst.pm b/lib/Catalyst.pm index 81d2a94..17c9403 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/; @@ -78,7 +79,7 @@ __PACKAGE__->stats_class('Catalyst::Stats'); # Remember to update this in Catalyst::Runtime as well! -our $VERSION = '5.80007'; +our $VERSION = '5.80011'; { my $dev_version = $VERSION =~ /_\d{2}$/; @@ -335,9 +336,11 @@ call to forward. $c->forward(qw/MyApp::Model::DBIC::Foo do_stuff/); $c->forward('MyApp::View::TT'); -Note that forward implies an C<> around the call (actually -C does), thus de-fatalizing all 'dies' within the called -action. If you want C to propagate you need to do something like: +Note that L<< forward|/"$c->forward( $action [, \@arguments ] )" >> implies +an C<< eval { } >> around the call (actually +L<< execute|/"$c->execute( $class, $coderef )" >> does), thus de-fatalizing +all 'dies' within the called action. If you want C to propagate you +need to do something like: $c->forward('foo'); die $c->error if $c->error; @@ -357,8 +360,8 @@ sub forward { my $c = shift; no warnings 'recursion'; $c->dispatcher->forward( $ =head2 $c->detach() -The same as C, but doesn't return to the previous action when -processing is finished. +The same as L<< forward|/"$c->forward( $action [, \@arguments ] )" >>, but +doesn't return to the previous action when processing is finished. When called with no arguments it escapes the processing chain entirely. @@ -370,23 +373,27 @@ sub detach { my $c = shift; $c->dispatcher->detach( $c, @_ ) } =head2 $c->visit( $class, $method, [, \@captures, \@arguments ] ) -Almost the same as C, but does a full dispatch, instead of just -calling the new C<$action> / C<$class-E$method>. This means that C, -C and the method you go to are called, just like a new request. +Almost the same as L<< forward|/"$c->forward( $action [, \@arguments ] )" >>, +but does a full dispatch, instead of just calling the new C<$action> / +C<< $class->$method >>. This means that C, C and the method +you go to are called, just like a new request. In addition both C<< $c->action >> and C<< $c->namespace >> are localized. -This means, for example, that $c->action methods such as C, C and -C return information for the visited action when they are invoked -within the visited action. This is different from the behavior of C -which continues to use the $c->action object from the caller action even when +This means, for example, that C<< $c->action >> methods such as +L, L and +L return information for the visited action +when they are invoked within the visited action. This is different from the +behavior of L<< forward|/"$c->forward( $action [, \@arguments ] )" >>, which +continues to use the $c->action object from the caller action even when invoked from the callee. -C<$c-Estash> is kept unchanged. +C<< $c->stash >> is kept unchanged. -In effect, C allows you to "wrap" another action, just as it -would have been called by dispatching from a URL, while the analogous -C allows you to transfer control to another action as if it had -been reached directly from a URL. +In effect, L<< visit|/"$c->visit( $action [, \@captures, \@arguments ] )" >> +allows you to "wrap" another action, just as it would have been called by +dispatching from a URL, while the analogous +L<< go|/"$c->go( $action [, \@captures, \@arguments ] )" >> allows you to +transfer control to another action as if it had been reached directly from a URL. =cut @@ -396,12 +403,12 @@ sub visit { my $c = shift; $c->dispatcher->visit( $c, @_ ) } =head2 $c->go( $class, $method, [, \@captures, \@arguments ] ) -Almost the same as C, but does a full dispatch like C, +Almost the same as L<< detach|/"$c->detach( $action [, \@arguments ] )" >>, but does a full dispatch like L, instead of just calling the new C<$action> / -C<$class-E$method>. This means that C, C and the +C<< $class->$method >>. This means that C, C and the method you visit are called, just like a new request. -C<$c-Estash> is kept unchanged. +C<< $c->stash >> is kept unchanged. =cut @@ -818,11 +825,11 @@ Returns or takes a hashref containing the application's configuration. __PACKAGE__->config( { db => 'dsn:SQLite:foo.db' } ); -You can also use a C, C or C config file -like myapp.conf in your applications home directory. See +You can also use a C, C or L config file +like C in your applications home directory. See L. -=head3 Cascading configuration. +=head3 Cascading configuration The config method is present on all Catalyst components, and configuration will be merged when an application is started. Configuration loaded with @@ -918,7 +925,7 @@ Returns the engine instance. See L. Merges C<@path> with C<< $c->config->{home} >> and returns a L object. Note you can usually use this object as a filename, but sometimes you will have to explicitly stringify it -yourself by calling the C<<->stringify>> method. +yourself by calling the C<< ->stringify >> method. For example: @@ -1158,36 +1165,54 @@ sub setup_finalize { $class->setup_finished(1); } -=head2 $c->uri_for( $action, \@captures?, @args?, \%query_values? ) - =head2 $c->uri_for( $path, @args?, \%query_values? ) -=over - -=item $action - -A Catalyst::Action object representing the Catalyst action you want to -create a URI for. To get one for an action in the current controller, -use C<< $c->action('someactionname') >>. To get one from different -controller, fetch the controller using C<< $c->controller() >>, then -call C on it. - -You can maintain the arguments captured by an action (e.g.: Regex, Chained) -using C<< $c->req->captures >>. +=head2 $c->uri_for( $action, \@captures?, @args?, \%query_values? ) - # For the current action - $c->uri_for($c->action, $c->req->captures); +Constructs an absolute L object based on the application root, the +provided path, and the additional arguments and query parameters provided. +When used as a string, provides a textual URI. + +If the first argument is a string, it is taken as a public URI path relative +to C<< $c->namespace >> (if it doesn't begin with a forward slash) or +relative to the application root (if it does). It is then merged with +C<< $c->request->base >>; any C<@args> are appended as additional path +components; and any C<%query_values> are appended as C parameters. + +If the first argument is a L it represents an action which +will have its path resolved using C<< $c->dispatcher->uri_for_action >>. The +optional C<\@captures> argument (an arrayref) allows passing the captured +variables that are needed to fill in the paths of Chained and Regex actions; +once the path is resolved, C continues as though a path was +provided, appending any arguments or parameters and creating an absolute +URI. + +The captures for the current request can be found in +C<< $c->request->captures >>, and actions can be resolved using +C<< Catalyst::Controller->action_for($name) >>. If you have a private action +path, use C<< $c->uri_for_action >> instead. + + # Equivalent to $c->req->uri + $c->uri_for($c->action, $c->req->captures, + @{ $c->req->args }, $c->req->params); # For the Foo action in the Bar controller - $c->uri_for($c->controller('Bar')->action_for('Foo'), $c->req->captures); + $c->uri_for($c->controller('Bar')->action_for('Foo')); -=back + # Path to a static resource + $c->uri_for('/static/images/logo.png'); =cut 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) @@ -1606,25 +1631,6 @@ sub _stats_finish_execute { $c->stats->profile( end => $info ); } -=head2 $c->_localize_fields( sub { }, \%keys ); - -=cut - -#Why does this exist? This is no longer safe and WILL NOT WORK. -# it doesnt seem to be used anywhere. can we remove it? -sub _localize_fields { - my ( $c, $localized, $code ) = ( @_ ); - - my $request = delete $localized->{request} || {}; - my $response = delete $localized->{response} || {}; - - local @{ $c }{ keys %$localized } = values %$localized; - local @{ $c->request }{ keys %$request } = values %$request; - local @{ $c->response }{ keys %$response } = values %$response; - - $code->(); -} - =head2 $c->finalize Finalizes the request. @@ -2127,40 +2133,32 @@ 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. -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. +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. + +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 = sort { length $a <=> length $b } + $class->locate_components($config); my %comps = map { $_ => 1 } @comps; - 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 ) { @@ -2169,30 +2167,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 (@comps) { + $class->components->{ $component } = $class->setup_component($component); + for my $component ($class->expand_component_module( $component, $config )) { + next if $comps{$component}; + $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. + +=cut + +sub expand_component_module { + my ($class, $module) = @_; + return Devel::InnerPackage::list_packages( $module ); +} + =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); @@ -2206,16 +2250,12 @@ 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 } || {}; + # 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 ); }; @@ -2635,6 +2675,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 @@ -2683,7 +2735,7 @@ Wiki: =head2 L - The Catalyst Manual -=head2 L, L - Base classes for components +=head2 L, L - Base classes for components =head2 L - Core engine @@ -2735,16 +2787,22 @@ esskar: Sascha Kiefer fireartist: Carl Franks +frew: Arthur Axel "fREW" Schmidt + gabb: Danijel Milicevic Gary Ashton Jones Geoff Richards +hobbs: Andrew Rodland + ilmari: Dagfinn Ilmari Mannsåker jcamacho: Juan Camacho +jester: Jesse Sheidlower + jhannah: Jay Hannah Jody Belka @@ -2753,6 +2811,8 @@ Johan Lindstrom jon: Jon Schutz +konobi: Scott McWhirter + marcus: Marcus Ramberg miyagawa: Tatsuhiko Miyagawa @@ -2783,8 +2843,6 @@ random: Roland Lammel sky: Arthur Bergman -the_jester: Jesse Sheidlower - t0m: Tomas Doran Ulf Edvinsson