Skip to content

Commit

Permalink
Improved routing section
Browse files Browse the repository at this point in the history
  • Loading branch information
Jules Pietri authored and HeahDude committed Mar 27, 2019
1 parent fd8e772 commit 0f1f2ea
Show file tree
Hide file tree
Showing 13 changed files with 178 additions and 91 deletions.
91 changes: 53 additions & 38 deletions components/routing.rst
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ your autoloader to load the Routing component::

use Symfony\Component\Routing\Matcher\UrlMatcher;
use Symfony\Component\Routing\RequestContext;
use Symfony\Component\Routing\RouteCollection;
use Symfony\Component\Routing\Route;
use Symfony\Component\Routing\RouteCollection;

$route = new Route('/foo', ['_controller' => 'MyController']);
$routes = new RouteCollection();
Expand Down Expand Up @@ -82,20 +82,24 @@ be thrown.
Defining Routes
~~~~~~~~~~~~~~~

A full route definition can contain up to seven parts:
A full route definition can contain up to eight parts:

#. The URL path route. This is matched against the URL passed to the `RequestContext`,
and can contain named wildcard placeholders (e.g. ``{placeholders}``)
to match dynamic parts in the URL.
#. The URL pattern. This is matched against the URL passed to the
``RequestContext``. It is not a regular expression, but can contain named
wildcard placeholders (e.g. ``{slug}``) to match dynamic parts in the URL.
The component will create the regular expression from it.

#. An array of default values. This contains an array of arbitrary values
that will be returned when the request matches the route.
#. An array of default parameters. This contains an array of arbitrary values
that will be returned when the request matches the route. It is used by
convention to map a controller to the route.

#. An array of requirements. These define constraints for the values of the
placeholders as regular expressions.
placeholders in the pattern as regular expressions.

#. An array of options. These contain internal settings for the route and
are the least commonly needed.
#. An array of options. These contain advanced settings for the route and
can be used to control encoding or customize compilation.
See :ref:`routing-unicode-support` below. You can learn more about them by
reading :method:`Symfony\\Component\\Routing\\Route::setOptions` implementation.

#. A host. This is matched against the host of the request. See
:doc:`/routing/hostname_pattern` for more details.
Expand All @@ -105,6 +109,10 @@ A full route definition can contain up to seven parts:
#. An array of methods. These enforce a certain HTTP request method (``HEAD``,
``GET``, ``POST``, ...).

#. A condition, using the :doc:`/components/expression_language/syntax`.
A string that must evaluate to ``true`` so the route matches. See
:doc:`/routing/conditions` for more details.

Take the following route, which combines several of these ideas::

$route = new Route(
Expand All @@ -114,7 +122,8 @@ Take the following route, which combines several of these ideas::
[], // options
'{subdomain}.example.com', // host
[], // schemes
[] // methods
[], // methods
'context.getHost() matches "/(secure|admin).example.com/"' // condition
);

// ...
Expand All @@ -138,19 +147,22 @@ When using wildcards, these are returned in the array result when calling
``match``. The part of the path that the wildcard matched (e.g. ``2012-01``) is used
as value.

.. tip::
A placeholder matches any character except slashes ``/`` by default, unless you define
a specific requirement for it.
The reason is that they are used by convention to separate different placeholders.

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::
If you want a placeholder to match anything, it must be the last of the route::

$route = new Route(
'/start/{suffix}',
['suffix' => ''],
['suffix' => '.*']
);
$route = new Route(
'/start/{required}/{anything}',
['required' => 'default'], // should always be defined
['anything' => '.*'] // explicit requirement to allow "/"
);

Using Prefixes
~~~~~~~~~~~~~~
Learn more about it by reading :ref:`routing/slash_in_parameter`.

Using Prefixes and Collection Settings
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

You can add routes or other instances of
:class:`Symfony\\Component\\Routing\\RouteCollection` to *another* collection.
Expand All @@ -166,11 +178,12 @@ host to all routes of a subtree using methods provided by the
$subCollection->add(...);
$subCollection->addPrefix('/prefix');
$subCollection->addDefaults([...]);
$subCollection->addRequirements([]);
$subCollection->addOptions([]);
$subCollection->setHost('admin.example.com');
$subCollection->addRequirements([...]);
$subCollection->addOptions([...]);
$subCollection->setHost('{subdomain}.example.com');
$subCollection->setMethods(['POST']);
$subCollection->setSchemes(['https']);
$subCollection->setCondition('context.getHost() matches "/(secure|admin).example.com/"');

$rootCollection->addCollection($subCollection);

Expand Down Expand Up @@ -210,7 +223,7 @@ Generate a URL

While the :class:`Symfony\\Component\\Routing\\Matcher\\UrlMatcher` tries
to find a route that fits the given request you can also build a URL from
a certain route::
a certain route with the :class:`Symfony\\Component\\Routing\\Generator\\UrlGenerator`::

use Symfony\Component\Routing\Generator\UrlGenerator;
use Symfony\Component\Routing\RequestContext;
Expand Down Expand Up @@ -260,7 +273,7 @@ when the route doesn't exist::
Load Routes from a File
~~~~~~~~~~~~~~~~~~~~~~~

You've already seen how you can easily add routes to a collection right inside
You've already seen how you can 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
Expand Down Expand Up @@ -347,7 +360,7 @@ The all-in-one Router
~~~~~~~~~~~~~~~~~~~~~

The :class:`Symfony\\Component\\Routing\\Router` class is an all-in-one package
to quickly use the Routing component. The constructor expects a loader instance,
to use the Routing component. The constructor expects a loader instance,
a path to the main route definition and some other settings::

public function __construct(
Expand All @@ -372,14 +385,17 @@ automatically in the background if you want to use it. A basic example of the
['cache_dir' => __DIR__.'/cache'],
$requestContext
);
$router->match('/foo/bar');
$parameters = $router->match('/foo/bar');
$url = $router->generate('some_route', ['parameter' => 'value']);

.. note::

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.

.. _routing-unicode-support:

Unicode Routing Support
~~~~~~~~~~~~~~~~~~~~~~~

Expand Down Expand Up @@ -481,7 +497,7 @@ You can also include UTF-8 strings as routing requirements:
* @Route(
* "/category/{name}",
* name="route2",
* requirements={"default"="한국어"},
* defaults={"name": "한국어"},
* options={"utf8": true}
* )
*/
Expand All @@ -494,10 +510,10 @@ You can also include UTF-8 strings as routing requirements:
# app/config/routing.yml
route2:
path: /default/{default}
defaults: { _controller: 'AppBundle:Default:default' }
requirements:
default: "한국어"
path: /category/{name}
defaults:
_controller: 'AppBundle:Default:default'
name: '한국어'
options:
utf8: true
Expand All @@ -510,9 +526,9 @@ You can also include UTF-8 strings as routing requirements:
xsi:schemaLocation="http://symfony.com/schema/routing
https://symfony.com/schema/routing/routing-1.0.xsd">
<route id="route2" path="/default/{default}">
<route id="route2" path="/category/{name}">
<default key="_controller">AppBundle:Default:default</default>
<requirement key="default">한국어</requirement>
<default key="name">한국어</requirement>
<option key="utf8">true</option>
</route>
</routes>
Expand All @@ -527,10 +543,9 @@ You can also include UTF-8 strings as routing requirements:
$routes->add('route2', new Route('/default/{default}',
[
'_controller' => 'AppBundle:Default:default',
'name' => '한국어',
],
[
'default' => '한국어',
],
[],
[
'utf8' => true,
]
Expand Down
49 changes: 35 additions & 14 deletions routing.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@
Routing
=======

Beautiful URLs are an absolute must for any serious web application. This
means leaving behind ugly URLs like ``index.php?article_id=57`` in favor
of something like ``/read/intro-to-symfony``.
Beautiful URLs are a must for any serious web application. This means leaving
behind ugly URLs like ``index.php?article_id=57`` in favor of something like
``/read/intro-to-symfony``.

Having flexibility is even more important. What if you need to change the
URL of a page from ``/blog`` to ``/news``? How many links should you need to
URL of a page from ``/blog`` to ``/news``? How many links would you need to
hunt down and update to make the change? If you're using Symfony's router,
the change is simple.
the change should be trivial.

The Symfony router lets you define creative URLs that you map to different
areas of your application. By the end of this article, you'll be able to:
Expand All @@ -27,10 +27,13 @@ areas of your application. By the end of this article, you'll be able to:
Routing Examples
----------------

A *route* is a map from a URL path to a controller. For example, suppose
you want to match any URL like ``/blog/my-post`` or ``/blog/all-about-symfony``
and send it to a controller that can look up and render that blog post.
The route is simple:
A *route* is a map from a URL path to attributes (i.e a controller). Suppose
you want one route that matches ``/blog`` exactly and another more dynamic
route that can match *any* URL like ``/blog/my-post`` or
``/blog/all-about-symfony``.

Routes can be configured in YAML, XML, PHP or annotations. All formats provide
the same features and performance, so choose the one you prefer:

.. configuration-block::

Expand All @@ -56,6 +59,7 @@ The route is simple:
/**
* Matches /blog/*
* but not /blog/slug/extra-part
*
* @Route("/blog/{slug}", name="blog_show")
*/
Expand All @@ -72,10 +76,13 @@ The route is simple:
# app/config/routing.yml
blog_list:
# Matches /blog exactly
path: /blog
defaults: { _controller: AppBundle:Blog:list }
blog_show:
# Matches /blog/*
# but not /blog/slug/extra-part
path: /blog/{slug}
defaults: { _controller: AppBundle:Blog:show }
Expand All @@ -88,10 +95,13 @@ The route is simple:
xsi:schemaLocation="http://symfony.com/schema/routing
https://symfony.com/schema/routing/routing-1.0.xsd">
<!-- Matches /blog exactly -->
<route id="blog_list" path="/blog">
<default key="_controller">AppBundle:Blog:list</default>
</route>
<!-- Matches /blog/* -->
<!-- but not /blog/slug/extra-part -->
<route id="blog_show" path="/blog/{slug}">
<default key="_controller">AppBundle:Blog:show</default>
</route>
Expand All @@ -104,9 +114,12 @@ The route is simple:
use Symfony\Component\Routing\Route;
$routes = new RouteCollection();
// Matches /blog exactly
$routes->add('blog_list', new Route('/blog', [
'_controller' => 'AppBundle:Blog:list',
]));
// Matches /blog/*
// but not /blog/slug/extra-part
$routes->add('blog_show', new Route('/blog/{slug}', [
'_controller' => 'AppBundle:Blog:show',
]));
Expand All @@ -119,13 +132,21 @@ Thanks to these two routes:
is executed;

* If the user goes to ``/blog/*``, the second route is matched and ``showAction()``
is executed. Because the route path is ``/blog/{slug}``, a ``$slug`` variable is
passed to ``showAction()`` matching that value. For example, if the user goes to
is executed. Because the route path is ``/blog/{slug}``, a ``$slug`` variable
is passed to ``showAction()`` matching that value. For example, if the user goes to
``/blog/yay-routing``, then ``$slug`` will equal ``yay-routing``.

Whenever you have a ``{placeholder}`` in your route path, that portion becomes a
wildcard: it matches *any* value. Your controller can now *also* have an argument
called ``$placeholder`` (the wildcard and argument names *must* match).
Whenever you have a ``{placeholder}`` in your route path, that portion becomes
a wildcard: it matches *any* value. Your controller can now *also* have an
argument called ``$placeholder`` (the wildcard and argument names *must*
match).

.. caution::

However the slash ``/`` is ignored by default in placeholder values because
the router uses it as separator between different placeholders.
To learn more about this, you can read
:ref:`routing/slash_in_parameter`.

Each route also has an internal name: ``blog_list`` and ``blog_show``. These can
be anything (as long as each is unique) and don't have any meaning yet.
Expand Down
2 changes: 1 addition & 1 deletion routing/conditions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ How to Restrict Route Matching through Conditions

A route can be made to match only certain routing placeholders (via regular
expressions), HTTP methods, or host names. If you need more flexibility to
define arbitrary matching logic, use the ``conditions`` routing option:
define arbitrary matching logic, use the ``condition`` routing setting:

.. configuration-block::

Expand Down
17 changes: 11 additions & 6 deletions routing/custom_route_loader.rst
Original file line number Diff line number Diff line change
Expand Up @@ -102,11 +102,17 @@ and configure the service and method to call:
return $routes;
In this example, the routes are loaded by calling the ``loadRoutes()`` method of
the service whose ID is ``admin_route_loader``. Your service doesn't have to
In this example, the routes are loaded by calling the ``loadRoutes()`` method
of the service whose ID is ``admin_route_loader``. Your service doesn't have to
extend or implement any special class, but the called method must return a
:class:`Symfony\\Component\\Routing\\RouteCollection` object.

.. note::

The routes defined using service route loaders will be automatically
cached by the framework. So whenever your service should load new routes,
don't forget to clear the cache.

Creating a custom Loader
------------------------

Expand Down Expand Up @@ -219,8 +225,7 @@ Now define a service for the ``ExtraLoader``:
use AppBundle\Routing\ExtraLoader;
$container
->autowire(ExtraLoader::class)
$container->autowire(ExtraLoader::class)
->addTag('routing.loader')
;
Expand All @@ -229,7 +234,7 @@ as potential route loaders and added as specialized route loaders to the
``routing.loader`` *service*, which is an instance of
:class:`Symfony\\Bundle\\FrameworkBundle\\Routing\\DelegatingLoader`.

Using the custom Loader
Using the Custom Loader
~~~~~~~~~~~~~~~~~~~~~~~

If you did nothing else, your custom routing loader would *not* be called.
Expand Down Expand Up @@ -276,7 +281,7 @@ for the ``ExtraLoader``, so it is set to ".".
cached by the framework. So whenever you change something in the loader
class itself, don't forget to clear the cache.

More advanced Loaders
More Advanced Loaders
---------------------

If your custom route loader extends from
Expand Down
Loading

0 comments on commit 0f1f2ea

Please sign in to comment.