update distar url
[catagits/Catalyst-Runtime.git] / lib / Catalyst / RouteMatching.pod
index e5f567c..9ca71ab 100644 (file)
@@ -25,7 +25,7 @@ that if the request is '/foo/bar/baz' That means the action 'baz' matches:
     sub bar :Path('bar') Args(1) { ...}
     sub baz :Path('bar/baz') Args(0) { ... }
 
-Path length matches take precidence over all other types of matches (included HTTP
+Path length matches take precedence over all other types of matches (included HTTP
 Method, Scheme, etc.).  The same holds true for Chained actions.  Generally the
 chain that matches the most PathParts wins.
 
@@ -37,7 +37,7 @@ action with 'Args' always get the last chance to match.
 
 =head2 When two or more actions match a given Path
 
-Sometimes two or more actions match the same path and all have the same pathpart
+Sometimes two or more actions match the same path and all have the same PathPart
 length.  For example:
 
     package MyApp::Controller::Root;
@@ -80,7 +80,7 @@ your 'catchall' actions higher in the controller.
 =head2 Type Constraints in Args and Capture Args
 
 Beginning in Version 5.90090+ you may use L<Moose>, L<MooseX::Types> or L<Type::Tiny>
-type constraints to futher declare allowed matching for Args or CaptureArgs.  Here
+type constraints to further declare allowed matching for Args or CaptureArgs.  Here
 is a simple example:
 
     package MyApp::Controller::User;
@@ -136,7 +136,7 @@ the L<Types::Standard> library that is packaged with L<Type::Tiny>:
     use Moose;
     use MooseX::MethodAttributes;
     use Types::Standard qw/StrMatch Int/;
-    
+
     extends 'Catalyst::Controller';
 
     sub looks_like_a_date :Path('') Args(StrMatch[qr{\d\d-\d\d-\d\d}]) {
@@ -152,10 +152,119 @@ A tutorial on how to make custom type libraries is outside the scope of this doc
 recommend looking at the copious documentation in L<Type::Tiny> or in L<MooseX::Types> if
 you prefer that system.  The author recommends L<Type::Tiny> if you are unsure which to use.
 
+=head3 Type constraint namespace.
+
+By default we assume the namespace which defines the type constraint is in the package
+which contains the action declaring the arg or capture arg.  However if you do not wish
+to import type constraints into you package, you may use a fully qualified namespace for
+your type constraint.  If you do this you must install L<Type::Tiny> which defines the
+code used to lookup and normalize the various types of Type constraint libraries.
+
+Example:
+
+    package MyApp::Example;
+
+    use Moose;
+    use MooseX::MethodAttributes;
+
+    extends 'Catalyst::Controller';
+
+    sub an_int_ns :Local Args(MyApp::Types::Int) {
+      my ($self, $c, $int) = @_;
+      $c->res->body('an_int (withrole)');
+    }
+
+Would basically work the same as:
+
+    package MyApp::Example;
+
+    use Moose;
+    use MooseX::MethodAttributes;
+    use MyApp::Types 'Int';
+
+    extends 'Catalyst::Controller';
+
+    sub an_int_ns :Local Args(Int) {
+      my ($self, $c, $int) = @_;
+      $c->res->body('an_int (withrole)');
+    }
+
+=head3 namespace::autoclean
+
+If you want to use L<namespace::autoclean> in your controllers you must 'except' imported
+type constraints since the code that resolves type constraints in args / capture args
+run after the cleaning.  For example:
+
+    package MyApp::Controller::Autoclean;
+
+    use Moose;
+    use MooseX::MethodAttributes;
+    use namespace::autoclean -except => 'Int';
+    use MyApp::Types qw/Int/;
+
+    extends 'Catalyst::Controller';
+
+    sub an_int :Local Args(Int) {
+      my ($self, $c, $int) = @_;
+      $c->res->body('an_int (autoclean)');
+    }
+
+=head3 Using roles and base controller with type constraints
+
+If your controller is using a base class or a role that has an action with a type constraint
+you should declare your use of the type constraint in that role or base controller in the
+same way as you do in main controllers.  Catalyst will try to find the package with declares
+the type constraint first by looking in any roles and then in superclasses.  It will use the
+first package that defines the type constraint.  For example:
+
+    package MyApp::Role;
+
+    use Moose::Role;
+    use MooseX::MethodAttributes::Role;
+    use MyApp::Types qw/Int/;
+
+    sub an_int :Local Args(Int) {
+      my ($self, $c, $int) = @_;
+      $c->res->body('an_int (withrole)');
+    }
+
+    sub an_int_ns :Local Args(MyApp::Types::Int) {
+      my ($self, $c, $int) = @_;
+      $c->res->body('an_int (withrole)');
+    }
+
+    package MyApp::BaseController;
+
+    use Moose;
+    use MooseX::MethodAttributes;
+    use MyApp::Types qw/Int/;
+
+    extends 'Catalyst::Controller';
+
+    sub from_parent :Local Args(Int) {
+      my ($self, $c, $id) = @_;
+      $c->res->body('from_parent $id');
+    }
+
+    package MyApp::Controller::WithRole;
+
+    use Moose;
+    use MooseX::MethodAttributes;
+
+    extends 'MyApp::BaseController';
+
+    with 'MyApp::Role';
+
+If you have complex controller hierarchy, we
+do not at this time attempt to look for all packages with a match type constraint, but instead
+take the first one found.  In the future we may add code that attempts to insure a sane use
+of subclasses with type constraints but right now there are no clear use cases so report issues
+and interests.
+
 =head3 Match order when more than one Action matches a path.
 
 As previously described, L<Catalyst> will match 'the longest path', which generally means
-that named path / path_parts will take precidence over Args or CaptureArgs.  However, what
+that named path / path_parts will take precedence over Args or CaptureArgs.  However, what
 will happen if two actions match the same path with equal args?  For example:
 
     sub an_int :Path(user) Args(Int) {
@@ -177,7 +286,7 @@ action NEVER gets hit.  You would need to reverse the order:
 
 Now requests that match this path would first hit the 'an_int' action and will check to see if
 the argument is an integer.  If it is, then the action will execute, otherwise it will pass and
-the dispatcher will check the next matching action (in this case we fall thru to the 'an_any'
+the dispatcher will check the next matching action (in this case we fall through to the 'an_any'
 action).
 
 =head3 Type Constraints and Chained Actions
@@ -187,7 +296,7 @@ actions.  The only difference is that you may declare type constraints on Captur
 well as Args.  For Example:
 
   use Types::Standard qw/Int Tuple/;
-  
+
   sub chain_base :Chained(/) CaptureArgs(1) { }
 
     sub any_priority_chain :GET Chained(chain_base) PathPart('') Args(1) {  }
@@ -199,7 +308,7 @@ well as Args.  For Example:
       sub any_priority_link_any :Chained(link_any) PathPart('') Args(1) {  }
 
       sub int_priority_link_any :Chained(link_any) PathPart('') Args(Int) {  }
-    
+
     sub link_int :Chained(chain_base) PathPart('') CaptureArgs(Int) { }
 
       sub any_priority_link :Chained(link_int) PathPart('') Args(1) {  }
@@ -218,7 +327,7 @@ well as Args.  For Example:
 
       sub int_priority_link3 :Chained(link_tuple) PathPart('') Args(Int) {  }
 
-These chained actions migth create match tables like the following:
+These chained actions might create match tables like the following:
 
     [debug] Loaded Chained actions:
     .-------------------------------------+--------------------------------------.
@@ -267,7 +376,7 @@ the rule described in the previous section should be followed, which is that L<C
 will start with the last defined action and work upward.  For example the action C<int_priority_chain>
 would be checked before C<any_priority_chain>.  The same applies for actions that are midway links
 in a longer chain.  In this case C<link_int> would be checked before C<link_any>.  So as always we
-recommend that you place you priority or most constrainted actions last and you least or catch-all
+recommend that you place you priority or most constrained actions last and you least or catch-all
 actions first.
 
 Although this reverse order checking may seen counter intuitive it does have the added benefit that