Revert "removed component resolution regex fallback"
[catagits/Catalyst-Runtime.git] / lib / Catalyst.pm
index d5f5ec8..9e41ec6 100644 (file)
@@ -560,9 +560,48 @@ sub _comp_names_search_prefixes {
 
     return @result if @result;
 
-    $c->log->warn("Looking for '$name', but nothing was found.");
+    # if we were given a regexp to search against, we're done.
+    return if ref $name;
+
+    # skip regexp fallback if configured
+    return
+        if $appclass->config->{disable_component_resolution_regex_fallback};
+
+    # regexp fallback
+    $query  = qr/$name/i;
+    @result = grep { $eligible{ $_ } =~ m{$query} } keys %eligible;
+
+    # no results? try against full names
+    if( !@result ) {
+        @result = grep { m{$query} } keys %eligible;
+    }
+
+    # don't warn if we didn't find any results, it just might not exist
+    if( @result ) {
+        # Disgusting hack to work out correct method name
+        my $warn_for = lc $prefixes[0];
+        my $msg = "Used regexp fallback for \$c->${warn_for}('${name}'), which found '" .
+           (join '", "', @result) . "'. Relying on regexp fallback behavior for " .
+           "component resolution is unreliable and unsafe.";
+        my $short = $result[0];
+        # remove the component namespace prefix
+        $short =~ s/.*?(Model|Controller|View):://;
+        my $shortmess = Carp::shortmess('');
+        if ($shortmess =~ m#Catalyst/Plugin#) {
+           $msg .= " You probably need to set '$short' instead of '${name}' in this " .
+              "plugin's config";
+        } elsif ($shortmess =~ m#Catalyst/lib/(View|Controller)#) {
+           $msg .= " You probably need to set '$short' instead of '${name}' in this " .
+              "component's config";
+        } else {
+           $msg .= " You probably meant \$c->${warn_for}('$short') instead of \$c->${warn_for}('${name}'), " .
+              "but if you really wanted to search, pass in a regexp as the argument " .
+              "like so: \$c->${warn_for}(qr/${name}/)";
+        }
+        $c->log->warn( "${msg}$shortmess" );
+    }
 
-    return;
+    return @result;
 }
 
 # Find possible names for a prefix
@@ -793,6 +832,12 @@ should be used instead.
 If C<$name> is a regexp, a list of components matched against the full
 component name will be returned.
 
+If Catalyst can't find a component by name, it will fallback to regex
+matching by default. To disable this behaviour set
+disable_component_resolution_regex_fallback to a true value.
+
+    __PACKAGE__->config( disable_component_resolution_regex_fallback => 1 );
+
 =cut
 
 sub component {
@@ -815,9 +860,21 @@ sub component {
             my( $comp ) = $c->_comp_search_prefixes( $name, qw/Model M Controller C View V/ );
             return $c->_filter_component( $comp, @args ) if $comp;
         }
-        else {
-            my @result = grep { m{$name} } keys %{ $c->components };
-            return map { $c->_filter_component( $_, @args ) } @result;
+
+        return
+            if $c->config->{disable_component_resolution_regex_fallback};
+
+        # This is here so $c->comp( '::M::' ) works
+        my $query = ref $name ? $name : qr{$name}i;
+
+        my @result = grep { m{$query} } keys %{ $c->components };
+        return map { $c->_filter_component( $_, @args ) } @result if ref $name;
+
+        if( $result[ 0 ] ) {
+            $c->log->warn( Carp::shortmess(qq(Found results for "${name}" using regexp fallback)) );
+            $c->log->warn( 'Relying on the regexp fallback behavior for component resolution' );
+            $c->log->warn( 'is unreliable and unsafe. You have been warned' );
+            return $c->_filter_component( $result[ 0 ], @args );
         }
 
         # I would expect to return an empty list here, but that breaks back-compat
@@ -2869,6 +2926,14 @@ C<default_view> - The default view to be rendered or returned when C<< $c->view
 
 =item *
 
+C<disable_component_resolution_regex_fallback> - Turns
+off the deprecated component resolution functionality so
+that if any of the component methods (e.g. C<< $c->controller('Foo') >>)
+are called then regex search will not be attempted on string values and
+instead C<undef> will be returned.
+
+=item *
+
 C<home> - The application home directory. In an uninstalled application,
 this is the top level application directory. In an installed application,
 this will be the directory containing C<< MyApp.pm >>.