发布于 2015-08-27 16:47:20 | 178 次阅读 | 评论: 0 | 来源: 网络整理
The Routing component maps an HTTP request to a set of configuration variables.
You can install the component in 2 different ways:
symfony/routing
on Packagist);In order to set up a basic routing system you need three parts:
RouteCollection
, which contains the route definitions (instances of the class Route
)RequestContext
, which has information about the requestUrlMatcher
, which performs the mapping of the request to a single routeHere is a quick example. Notice that this assumes that you’ve already configured your autoloader to load the Routing component:
use SymfonyComponentRoutingMatcherUrlMatcher;
use SymfonyComponentRoutingRequestContext;
use SymfonyComponentRoutingRouteCollection;
use SymfonyComponentRoutingRoute;
$route = new Route('/foo', array('controller' => 'MyController'));
$routes = new RouteCollection();
$routes->add('route_name', $route);
$context = new RequestContext($_SERVER['REQUEST_URI']);
$matcher = new UrlMatcher($routes, $context);
$parameters = $matcher->match('/foo');
// array('controller' => 'MyController', '_route' => 'route_name')
注解
Be careful when using $_SERVER['REQUEST_URI']
, as it may include
any query parameters on the URL, which will cause problems with route
matching. An easy way to solve this is to use the HttpFoundation component
as explained below.
You can add as many routes as you like to a
RouteCollection
.
The RouteCollection::add()
method takes two arguments. The first is the name of the route. The second
is a Route
object, which expects a
URL path and some array of custom variables in its constructor. This array
of custom variables can be anything that’s significant to your application,
and is returned when that route is matched.
If no matching route can be found a
ResourceNotFoundException
will be thrown.
In addition to your array of custom variables, a _route
key is added,
which holds the name of the matched route.
A full route definition can contain up to seven parts:
{placeholders}
)
to match dynamic parts in the URL.http
, https
).HEAD
,
GET
, POST
, ...).Take the following route, which combines several of these ideas:
$route = new Route(
'/archive/{month}', // path
array('controller' => 'showArchive'), // default values
array('month' => '[0-9]{4}-[0-9]{2}', 'subdomain' => 'www|m'), // requirements
array(), // options
'{subdomain}.example.com', // host
array(), // schemes
array() // methods
);
// ...
$parameters = $matcher->match('/archive/2012-01');
// array(
// 'controller' => 'showArchive',
// 'month' => '2012-01',
// 'subdomain' => 'www',
// '_route' => ...
// )
$parameters = $matcher->match('/archive/foo');
// throws ResourceNotFoundException
In this case, the route is matched by /archive/2012-01
, because the {month}
wildcard matches the regular expression wildcard given. However, /archive/foo
does not match, because “foo” fails the month wildcard.
小技巧
If you want to match all URLs which start with a certain path and end in an arbitrary suffix you can use the following route definition:
$route = new Route(
'/start/{suffix}',
array('suffix' => ''),
array('suffix' => '.*')
);
You can add routes or other instances of
RouteCollection
to another collection.
This way you can build a tree of routes. Additionally you can define a prefix
and default values for the parameters, requirements, options, schemes and the
host to all routes of a subtree using methods provided by the
RouteCollection
class:
$rootCollection = new RouteCollection();
$subCollection = new RouteCollection();
$subCollection->add(...);
$subCollection->add(...);
$subCollection->addPrefix('/prefix');
$subCollection->addDefaults(array(...));
$subCollection->addRequirements(array(...));
$subCollection->addOptions(array(...));
$subCollection->setHost('admin.example.com');
$subCollection->setMethods(array('POST'));
$subCollection->setSchemes(array('https'));
$rootCollection->addCollection($subCollection);
The RequestContext
provides information
about the current request. You can define all parameters of an HTTP request
with this class via its constructor:
public function __construct(
$baseUrl = '',
$method = 'GET',
$host = 'localhost',
$scheme = 'http',
$httpPort = 80,
$httpsPort = 443,
$path = '/',
$queryString = ''
)
Normally you can pass the values from the $_SERVER
variable to populate the
RequestContext
. But If you use the
HttpFoundation component, you can use its
Request
class to feed the
RequestContext
in a shortcut:
use SymfonyComponentHttpFoundationRequest;
$context = new RequestContext();
$context->fromRequest(Request::createFromGlobals());
While the UrlMatcher
tries
to find a route that fits the given request you can also build a URL from
a certain route:
use SymfonyComponentRoutingGeneratorUrlGenerator;
$routes = new RouteCollection();
$routes->add('show_post', new Route('/show/{slug}'));
$context = new RequestContext($_SERVER['REQUEST_URI']);
$generator = new UrlGenerator($routes, $context);
$url = $generator->generate('show_post', array(
'slug' => 'my-blog-post',
));
// /show/my-blog-post
注解
If you have defined a scheme, an absolute URL is generated if the scheme
of the current RequestContext
does
not match the requirement.
You’ve already seen how you can easily add routes to a collection right inside PHP. But you can also load routes from a number of different files.
The Routing component comes with a number of loader classes, each giving
you the ability to load a collection of route definitions from an external
file of some format.
Each loader expects a FileLocator
instance
as the constructor argument. You can use the FileLocator
to define an array of paths in which the loader will look for the requested files.
If the file is found, the loader returns a RouteCollection
.
If you’re using the YamlFileLoader
, then route definitions look like this:
# routes.yml
route1:
path: /foo
defaults: { _controller: 'MyController::fooAction' }
route2:
path: /foo/bar
defaults: { _controller: 'MyController::foobarAction' }
To load this file, you can use the following code. This assumes that your
routes.yml
file is in the same directory as the below code:
use SymfonyComponentConfigFileLocator;
use SymfonyComponentRoutingLoaderYamlFileLoader;
// look inside *this* directory
$locator = new FileLocator(array(__DIR__));
$loader = new YamlFileLoader($locator);
$collection = $loader->load('routes.yml');
Besides YamlFileLoader
there are two
other loaders that work the same way:
If you use the PhpFileLoader
you
have to provide the name of a PHP file which returns a RouteCollection
:
// RouteProvider.php
use SymfonyComponentRoutingRouteCollection;
use SymfonyComponentRoutingRoute;
$collection = new RouteCollection();
$collection->add(
'route_name',
new Route('/foo', array('controller' => 'ExampleController'))
);
// ...
return $collection;
There is also the ClosureLoader
, which
calls a closure and uses the result as a RouteCollection
:
use SymfonyComponentRoutingLoaderClosureLoader;
$closure = function () {
return new RouteCollection();
};
$loader = new ClosureLoader();
$collection = $loader->load($closure);
Last but not least there are
AnnotationDirectoryLoader
and
AnnotationFileLoader
to load
route definitions from class annotations. The specific details are left
out here.
The Router
class is an all-in-one package
to quickly use the Routing component. The constructor expects a loader instance,
a path to the main route definition and some other settings:
public function __construct(
LoaderInterface $loader,
$resource,
array $options = array(),
RequestContext $context = null,
array $defaults = array()
);
With the cache_dir
option you can enable route caching (if you provide a
path) or disable caching (if it’s set to null
). The caching is done
automatically in the background if you want to use it. A basic example of the
Router
class would look like:
$locator = new FileLocator(array(__DIR__));
$requestContext = new RequestContext($_SERVER['REQUEST_URI']);
$router = new Router(
new YamlFileLoader($locator),
'routes.yml',
array('cache_dir' => __DIR__.'/cache'),
$requestContext
);
$router->match('/foo/bar');
注解
If you use caching, the Routing component will compile new classes which
are saved in the cache_dir
. This means your script must have write
permissions for that location.