Toro is a PHP router for developing RESTful web applications and APIs. It is designed for minimalists who want to get work done.
- RESTful routing using strings, regular expressions, and defined types
(
number
,string
,alpha
) - Flexible error handling and callbacks via
ToroHook
- Intuitive and self-documented core (
Toro.php
) - Tested with PHP 5.3 and above
The canonical "Hello, world" example:
<?php
class HelloHandler {
function get() {
echo "Hello, world";
}
}
Toro::serve(array(
"/" => "HelloHandler",
));
Routing with Toro is simple:
<?php
Toro::serve(array(
"/" => "SplashHandler",
"/catalog/page/:number" => "CatalogHandler",
"/product/:alpha" => "ProductHandler",
"/manufacturer/:string" => "ManufacturerHandler"
));
An application's route table is expressed as an associative array
(route_pattern => handler
). This is closely modeled after
Tornado (Python). Routes are not expressed as
anonymous functions to prevent unnecessary code duplication for RESTful
dispatching.
From the above example, route stubs, such as :number
, :string
, and
:alpha
can be conveniently used instead of common regular expressions.
Of course, regular expressions are still welcome. The previous example could
also be expressed as:
<?php
Toro::serve(array(
"/" => "SplashHandler",
"/catalog/page/([0-9]+)" => "CatalogHandler",
"/product/([a-zA-Z0-9-_]+)" => "ProductHandler",
"/manufacturer/([a-zA-Z]+)" => "ManufacturerHandler"
));
Pattern matches are passed in order as arguments to the handler's request
method. In the case of ProductHandler
above:
<?php
class ProductHandler {
function get($name) {
echo "You want to see product: $name";
}
}
<?php
class ExampleHandler {
function get() {}
function post() {}
function get_xhr() {}
function post_xhr() {}
}
From the above, you can see two emergent patterns.
-
Methods named after the HTTP request method (
GET
,POST
,PUT
,DELETE
) are automatically called. -
Appending
_xhr
to a handler method automatically matches JSON/XMLHTTPRequest
requests. If the_xhr
method is not implemented, then the given HTTP request method is called as a fallback.
As of v2.0.0, there are a total of five Toro-specific hooks (callbacks):
<?php
// Fired for 404 errors; must be defined before Toro::serve() call
ToroHook::add("404", function() {});
// Before/After callbacks in order
ToroHook::add("before_request", function() {});
ToroHook::add("before_handler", function() {});
ToroHook::add("after_handler", function() {});
ToroHook::add("after_request", function() {});
before_handler
and after_handler
are defined within handler's constructor:
<?php
class SomeHandler {
function __construct() {
ToroHook::add("before_handler", function() { echo "Before"; });
ToroHook::add("after_handler", function() { echo "After"; });
}
function get() {
echo "I am some handler.";
}
}
Hooks can also be stacked. Adding a hook pushes the provided anonymous function into an array. When a hook is fired, all of the functions are called sequentially.
Grab a copy of the repository and move Toro.php
to your project root.
Install composer in your project:
$ curl -s https://getcomposer.org/installer | php
Caution: The above command requires you to place a lot of trust in the composer team to not get hacked and have a backdoor installed in their installer script. If secuity is a concern, consider doing the following:
$ curl -s https://getcomposer.org/installer > installer.php
$ less installer.php
$ # When you're certain it's safe...
$ php installer.php
Create a composer.json
file in your project root:
{
"require": {
"torophp/torophp": "dev-master"
}
}
Install via composer:
$ php composer.phar install
You may need to add the following snippet in your Apache HTTP server virtual host configuration or .htaccess file.
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond $1 !^(index\.php)
RewriteRule ^(.*)$ /index.php/$1 [L]
Alternatively, if you’re lucky enough to be using a version of Apache greater than 2.2.15, then you can instead just use this one, single line:
FallbackResource /index.php
For IIS you will need to install URL Rewrite for IIS and then add the following rule to your web.config
:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<rewrite>
<rule name="Toro" stopProcessing="true">
<match url="^(.*)$" ignoreCase="false" />
<conditions logicalGrouping="MatchAll">
<add input="{REQUEST_FILENAME}" matchType="IsFile" ignoreCase="false" negate="true" />
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" ignoreCase="false" negate="true" />
<add input="{R:1}" pattern="^(index\.php)" ignoreCase="false" negate="true" />
</conditions>
<action type="Rewrite" url="/index.php/{R:1}" />
</rule>
</rewrite>
</system.webServer>
</configuration>
Under the server
block of your virtual host configuration, you only need to add three lines.
location / {
try_files $uri $uri/ /index.php?$query_string;
}
- Toro was inspired by the Tornado Web Server (FriendFeed/Facebook)
- Berker Peksag, Martin Bean, Robbie Coleman, and John Kurkowski for bug fixes and patches
- Danillo César de O. Melo for
ToroHook
- Jason Mooberry for code optimizations and feedback
Contributions to Toro are welcome via pull requests.
ToroPHP was created by Kunal Anand and released under the MIT License.