From 98c4ac0eb86c68ff1de5d55ea2b834c38a40cac0 Mon Sep 17 00:00:00 2001 From: PJ Dietz Date: Sat, 26 Jul 2014 17:19:48 -0400 Subject: [PATCH] Update README and add documentation/routes.md --- README.md | 20 ++++-- documentation/routes.md | 148 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 163 insertions(+), 5 deletions(-) create mode 100644 documentation/routes.md diff --git a/README.md b/README.md index eac8e47..81c6aa6 100644 --- a/README.md +++ b/README.md @@ -40,9 +40,7 @@ Examples ### Routing -WellRESTed's primary goal is to facilitate mapping of URIs to classes that will provide or accept representations. To do this, create a `Router` instance and load it up with some `Route`s. Each `Route` is simply a mapping of a URI pattern to a class name. The class name represents the `Handler` (any class implementing `HandlerInterface`) which the router will dispatch when it receives a request for the given URI. **The handlers are never instantiated or loaded unless they are needed.** - -Here's an example of a Router that will handle two URIs: +WellRESTed's primary goal is to facilitate mapping of URIs to classes that will provide or accept representations. To do this, create a `Router` instance and load it up with some `Route`s. Each `Route` is simply a mapping of a URI pattern to a class name. The class name represents the "handler" (any class implementing `HandlerInterface`) which the router will dispatch when it receives a request for the given URI. **The handlers are never instantiated or loaded unless they are needed.** ```php // Build the router. @@ -55,6 +53,9 @@ $myRouter->addRoutes(array( $myRouter->respond(); ``` +See [Routes](documentation/routes.md) to learn about the various route classes. + + ### Building Routes with JSON WellRESTed also provides a class to construct routes for you based on a JSON description. Here's an example. @@ -98,7 +99,7 @@ For most cases, you'll want to use a subclass of the `Handler` class, which prov If your endpoint should reject particular verbs, no worries. The Handler base class defines the default verb-handling methods to respond with a **405 Method Not Allowed** status. -Here's a simple Handler that matches the first endpoint, `/cats/`. +Here's a simple Handler that allows `GET` and `POST`. ```php class CatsCollectionHandler extends \pjdietz\WellRESTed\Handler @@ -128,14 +129,23 @@ class CatsCollectionHandler extends \pjdietz\WellRESTed\Handler } ``` -This Handler works with the endpoint, `/cats/{id}`. The template for this endpoint has the variable `{id}` in it. The Handler can access path variables through its `args` member, which is an associative array of variables from the URI. +#### Path Variables +When you use a `TemplateRoute` with variables (or a `RegexRoute` with capture groups), you can access the variables (or captures) through the `Handler` member variable `$args`. + +Create this route... +```php +$route = TemplateRoute("/cats/{id}", "CatItemHandler"); +``` + +...which dispatches a `CatItemHandler` instance. ```php class CatItemHandler extends \pjdietz\WellRESTed\Handler { protected function get() { // Find a cat ($cat) based on $this->args["id"] + $id = $this->args["id"] // ...do lookup here... if ($cat) { diff --git a/documentation/routes.md b/documentation/routes.md new file mode 100644 index 0000000..9ae9c74 --- /dev/null +++ b/documentation/routes.md @@ -0,0 +1,148 @@ +# Routes + +WellRESTed comes with a few Route classes: + +- `StaticRoute`: Matches requests paths exactly +- `TemplateRoute`: Matches URI templates +- `RegexRoute`: Matches a custom regular expression + +Each works basically the same way: It first checks to see if it is a match for the request. If it's a match, it instantiates a specific class implementing the `HandlerInterface` (autoloading the class, if needed). Finally, it uses the handler class to provide a response. + +If the route does not match the request, it returns `null`. + +## StaticRoute + +Use a `StaticRoute` when you know the exact path you want to handle. + +```php +$router = new Router(); +$router->addRoute(new StaticRoute("/", "RootHandler")); +$router->addRoute(new StaticRoute("/cats/", "CatCollectionHandler")); +$myRouter->respond(); +``` + +This `Router` will now use a `RootHandler` for requests for the path `/` and `CatCollectionHandler` for requests to `/cats/`. The router doesn't know about any other paths, so any other requests will result in a 404 Not Found response. + +You can also make a `StaticRoute` that matches multiple exact paths. For example, suppose you have a multi-use `AnimalHandler` that you want to invoke to handle requests to `/cats/`, `/dogs`, and `/birds`. You can make this by passing an array instead of a string as the first parameter. + +```php +$route = new StaticRoute(array("/cats/", "/dogs/", "/birds"), "AnimalHandler"); +``` + +## TemplateRoute + +`StaticRoutes` are the best choice if you know the exact path up front. But, what if you want to handle a path that expects an ID or other variable? That's where the `TemplateRoute` comes in. + +Here's a route that will match a request to a specific cat by ID and send it to a `CatItemHandler`. + +```php +$route = new TemplateRoute("/cats/{id}", "CatItemHandler"); +``` + +TemplateRoutes use URI templates to match requests to handlers. To include a variable in your template, enclose it in `{}`. The variable will be extracted and made available for the handler in the handler's `args` member. + +```php +class CatItemHandlder extends \pjdietz\WellRESTed\Handler +{ + protected function get() + { + // Access the {id} variable from the $this->args member. + $id = $this->args["id"]; + // ...Do something with the {id}. + } +} +``` + +Your template may have multiple variables. Be sure to give each a unique name. + +With this `TemplateRoute`... + +```php +$route = new TemplateRoute("/cats/{catId}/{dogId}", "CatItemHandler"); +``` + +...the handler will have access to `$this->args["catId"]` and `$this->args["dogId"]`. + + +### Default Variable Pattern + +By default, the `TemplateRoute` will accept for a variable any value consisting of numbers, letters, underscores, and hyphens. You can change this behavior by passing a pattern to use as the third parameter of the constructor. Here we'll restrict the template to only match numeric values. + +```php +$route = new TemplateRoute("/cats/{id}", "CatItemHandler", TemplateRoute::RE_NUM); +``` + +The `TemplateRoute` includes constants for some common situations. The value of each constant is a partial regular expression. You can use one of the constants, or provide your own partial regular expression. + +### Pattern Constants + +| Constant | Pattern | Description | +| --------- | ----------------- | ----------- | +| `RE_SLUG` | `[0-9a-zA-Z\-_]+` | "URL-friendly" characters such as numbers, letters, underscores, and hyphens | +| `RE_NUM` | `[0-9]+` | Digits only | +| `RE_ALPHA` | `[a-zA-Z]+` | Letters only | +| `RE_ALPHANUM` | `[0-9a-zA-Z]+` | Letters and digits | + +### Variable Patterns Array + +You can also set a different pattern for each variable. To do this, pass an array to the `TemplateRoute` constructor as the fourth paramter. The array must have variable names as keys and patterns as values. + +```php +$patterns = array( + "id" => TemplateRoute::RE_NUM, + "name" => TemplateRoute::RE_ALPHA, +); +$route = new TemplateRoute( + "/cats/{id}/{name}/{more}", + "CatItemHandler", + TemplateRoute::RE_SLUG, + $patterns); +``` + +Here, `{id}` will need to match digits, `{name}` must be all letters, and since `{more}` is not explicitly provided in the `$patterns` array, it uses the default `TemplateRoute::RE_SLUG` passed as the thrid parameter. + +### RegexRoute + +If `TemplateRoute` doesn't give you enough control, you can make a route that matches a regular expression. + +```php +$route = new RegexRoute("~/cat/[0-9]+~", "CatHandler") +``` + +This will match `/cat/102` or `/cat/999` or what have you. To make this more useful, we can add a capture group. The captures are made available to the `Handler` as the `$this->args` member, as with the URI template variables for the `TemplateRoute` + +Note the entire matched path will always be the `0` item, and captured groups will begin at `1`. + +So this route... + +```php +$route = new RegexRoute("~/cat/([0-9]+)~", "CatHandler") +``` + +...with the path `/cat/99` creates this array of matches: + +``` +Array +( + [0] => /cat/99 + [1] => 99 +) +``` + +You can also used named capture groups like this; + + +```php +$route = new RegexRoute("~/cat/(?[0-9]+)~", "CatHandler") +``` + +...with the path `/cat/99` creates this array or matches: + +``` +Array +( + [0] => /cat/99 + [1] => 99 + [id] => 99 +) +```