Skip to content
This repository was archived by the owner on Sep 16, 2021. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
231 changes: 153 additions & 78 deletions components/routing.rst
Original file line number Diff line number Diff line change
@@ -1,29 +1,31 @@
Routing Component
=================

The `Symfony2 CMF Routing component <https://github.com/symfony-cmf/Routing>`_
The `Symfony CMF Routing component <https://github.com/symfony-cmf/Routing>`_
library extends the Symfony2 core routing component. Even though it has Symfony
in its name, it does not need the full Symfony2 framework and can be used in
standalone projects. For integration with Symfony we provide
standalone projects. For integration with Symfony we provide
:doc:`../bundles/routing-extra`.

This component provides a ``ChainRouter`` that can chain several RouterInterface
instances one after the other. It uses a list of routers, ordered by a priority
value, the higher the priority number the earlier that router is asked to match
respectively generate routes. One of the routers in that chain can of course be
the Symfony2 router instance so you can still use the standard way for some of
your routes.
At the core of the Symfony CMF Routing component is the ``ChainRouter``, that
is used instead of the Symfony2's default routing system. The ChainRouter
can chain several ``RouterInterface`` implementations, one after the other,
to determine who should handle each request. The default Symfony2 router
can be added to this chain, so the standard routing mechanism can still be
used.

Additionally, this component is meant to provide useful router implementations.
Currently, there is the ``DynamicRouter`` that routes based on a implemented
repository that provide Symfony2 Route objects. The repository can be
implemented using a database, for example with doctrine PHPCR-ODM or doctrine
orm.
Additionally, this component is meant to provide useful ``RouterInterface``
implementations. Currently, it provides ``DynamicRouter`` that's able to
dynamically retrieve a Symfony2 Route object from a repository. The repository
can be implemented using a database, for example with Doctrine PHPCR-ODM
or Doctrine ORM.

Note: To use this component outside of the Symfony2 framework context, have
a look at the core Symfony2 `Routing <https://github.com/symfony/Routing>`_
to get a fundamental understanding of the component. CMF Routing just extends
the basic behaviour.
.. note::

To use this component outside of the Symfony2 framework context, have
a look at the core Symfony2 `Routing <https://github.com/symfony/Routing>`_
to get a fundamental understanding of the component. CMF Routing just extends
the basic behaviour.

.. index:: Routing

Expand All @@ -34,102 +36,175 @@ This component uses `composer <http://getcomposer.org>`_. It needs the
Symfony2 Routing component and the Symfony2 HttpKernel (for the logger
interface and cache warmup interface).

For the DynamicRouter you will need something to implement the
RouteRepositoryInterface with. We suggest using Doctrine as this allows to map
For the ``DynamicRouter`` you will need something to implement the
``RouteRepositoryInterface`` with. We suggest using Doctrine as this allows to map
any class into a database.

ChainRouter
-----------

The ChainRouter does not route anything on its own, but only loops through all
chained routers. Add your router instances with the ``add`` method, then try
to resolve routes with all added routers using the ``match`` method and
Please refer to the phpdoc comments on the public methods for details.
At the core of Symfony CMF's Routing component sits the ``ChainRouter``.
It's used as a replacement for Symfony2's default routing system, and is
responsible for determining which Controller will handle each request.

The ``ChainRouter`` works by accepting a set of prioritized routing strategies,
`RouterInterface <http://api.symfony.com/2.1/Symfony/Component/Routing/RouterInterface.html>`_
implementations, commonly referred to as "Routers".

When handling an incoming request, it will iterate over the configured Routers,
by their configured priority, until one of them is able to `match <http://api.symfony.com/2.1/Symfony/Component/Routing/RouterInterface.html#method_match>`_
the request and assign the request to a given Controller.

Routers
-------

The ``ChainRouter`` is incapable of, by itself, making any actual routing.
It's sole responsibility is managing the given set of Routers, which are the
true responsibles for the matching a request to a Controller.

You can easily create your own Routers by implementing `RouterInterface <http://api.symfony.com/2.1/Symfony/Component/Routing/RouterInterface.html>`_
but, by default, Symfony CMF already includes some basic routing mechanism to
help you get started.

.. note::

If you are using this as part of a full Symfony CMF project, please refer to
:doc:`../bundles/routing-extra` for instructions on how to add Routers to
the ``ChainRouter``. Otherwise, use the ``ChainRouter``'s ``add`` method to
configure new Routers.

Symfony2 Default Router
~~~~~~~~~~~~~~~~~~~~~~~

The Symfony2 routing mechanism is itself a ``RouterInterface`` implementation,
which means you can use it as a Router in the ``ChainRouter``. This allows you
to use the default routing declaration system.

Dynamic Router
--------------
~~~~~~~~~~~~~~

The ``DynamicRouter`` is capable of loading `Route <http://api.symfony.com/2.1/Symfony/Component/Routing/Route.html>`_
objects dynamically from a given data source provided to the Router as a
``RouteRepositoryInterface`` implementation. Although it can be used in other
ways, the ``RouteRepositoryInterface``'s main goal is to be easily implementented
on top of Doctrine PHPCR ODM, effectively allowing you to store and manage
routes dynamically from database.

This implementation of a router loads routes from a RouteRepositoryInterface.
This interface can be easily implemented with doctrine.
The router works with the base UrlMatcher and UrlGenerator classes and only
adds loading routes from the database and the concept of referenced content.
Request handling
^^^^^^^^^^^^^^^^

To instantiate a DynamicRouter, you need an implementation of the
RouteRepositoryInterface. See the `RoutingExtraBundle <https://github.com/symfony-cmf/RoutingExtraBundle>`_
document classes for an example.
The incoming request are handled by the ``DynamicRouter``'s ``match``
using the following workflow:

You will want to create controller mappers that decide what controller will
be used to handle the request, to avoid hard coding controller names into your
content.
* The ``DynamicRouter`` uses the ``RouteRepositoryInterface`` to fetch a set of ``Route`` instances
* The ``UrlMatcher`` is then used on the returned set to find a single matching ``Route``
* A set of optional ``RouteEnhancers`` is applied to the ``Route``

Match Process
~~~~~~~~~~~~~
The Fetching
""""""""""""

The match method of the DynamicRouter does the following steps
Based on the requested url, the ``DynamicRouter`` will retrieve a ordered
set of ``Route`` objects from the ``RouteRepositoryInterface``.

* Ask the repository for Route documents that could match the requested url
* Build a route collection and let the UrlMatcher find a matching route
* If the defaults do not contain the field _controller, loop through the
ControllerMapperInterface list to find the controller. If none of the
mapper finds a controller, throw a ResourceNotFoundException
* If the route implements RouteObjectInterface and returns a non-null content,
set it in the returned array with key ``_content``.
The underlying implementation of the ``RouteRepositoryInterface`` interface
is not part of this bundle's scope. Refer to the interface declaration for
more information. For a functional example, see `RoutingExtraBundle <https://github.com/symfony-cmf/RoutingExtraBundle>`_.

The Matching
""""""""""""

RouteObjectInterface
~~~~~~~~~~~~~~~~~~~~
The DynamicRouter uses Symfony Routing Component's `UrlMatcher <http://api.symfony.com/2.1/Symfony/Component/Routing/Matcher/UrlMatcher.html>`_
when iterating over the retrieved ``Route`` objects, in order to determine
which of them to use.

Routes that implement this interface can be linked to a content document using
the ``getRouteContent`` method. If non-null, this content is passed to the
controller. If there is no specific content for this route this may return null.
The Enhancers
"""""""""""""

Furthermore, routes that implement this interface can also provide a custom route
Optionally, a set of ``RouteEnhancerInterface`` instances can be declared and
associated with the DynamicRouter. The aim of these is to allow you to manipulate
the ``Route`` and its associated parameters. They can be used, for example,
to dynamically assign a controller or template to a ``Route``. Some simple
Enhancers are already packed with the bundle, documentation can be found
inside each class file.

Linking a Route with a Content
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Depending on you application's logic, a requested url may have an associated
content from the database. Those Routes should implement the ``RouteObjectInterface``,
and can optionally return a model instance, that will be bundled in the
returned array, in the ``_content`` key. Notice that a Route can implement
the above mentioned interface but still not to return any model instance,
in which case no associated object will be returned.

Furthermore, routes that implement this interface can also provide a custom Route
name. The key returned by ``getRouteKey`` will be used as route name instead of
the Symfony core compatible route name and can contain any characters. This allows
you, for example, to set a path as the route name.

All routes still need to extend the base class ``Symfony\Component\Routing\Route``
All routes still need to extend the base class ``Symfony\Component\Routing\Route``.

Redirections
~~~~~~~~~~~~
^^^^^^^^^^^^

You can build redirections with a RedirectRouteInterface document. It can
redirect either to an absolute URI, or to a named route that can be generated by
any router in the chain or to another Route object in the repository.
To handle it, you can make ControllerClassMapper map a suitable controller
to ``Symfony\Cmf\Component\Routing\RedirectRouteInterface``
You can build redirections by implementing the ``RedirectRouteInterface``.
It can redirect either to an absolute URI, to a named Route that can be
generated by any Router in the chain or to another Route object in the repository.

Notice that the actual redirection logic is not handled by the bundle. You
should implement your own logic to handle the actual redirection. For an
example on implementing that redirection under the full Symfony2 stack, refer
to :doc:`../bundles/routing-extra`.

Routes and locales
~~~~~~~~~~~~~~~~~~
^^^^^^^^^^^^^^^^^^

You can use the _locale default value in a route to create one route per locale
that all reference the same multilingual content.
The DynamicRouter respects the _locale when generating routes from content.
When resolving the route, the _locale gets into the request and is picked up
by the Symfony2 locale system.
You can use the ``_locale`` default value in a Route to create one Route
per locale that, all referencing the same multilingual model instance. The ``DynamicRouter``
respects the ``_locale`` when generating routes from model instances. When resolving
the route, the ``_locale`` gets into the request and is picked up by the Symfony2
locale system.

A note for PHPCR-ODM: Routes should never be translatable documents, as one
route document represents one single url, and serving several translations
under the same url is not a good idea.
.. note::

Under PHPCR-ODM, Routes should never be translatable documents, as one
Route document represents one single url, and serving several translations
under the same url is not recommended.

Customize
~~~~~~~~~

You can add more ControllerMapperInterface implementations if you have a case
not handled by the provided ones.
Url generation
^^^^^^^^^^^^^^

For more specific needs, have a look at DynamicRouter and see if you want to
extend it. You can also write your own routers to hook into the chain.
``DynamicRouter`` uses Symfony2's default `UrlGenerator <http://api.symfony.com/2.1/Symfony/Component/Routing/Generator/UrlGenerator.html>`_
to handle url generation. You can generate urls for your content in three ways:

Url generation
~~~~~~~~~~~~~~
* Either pass an implementation of ``RouteObjectInterface`` as ``route`` parameter
* Or pass a model instance as ``content`` parameter
* Or supply an implementation of ``ContentRepositoryInterface`` and the id of the model instance as parameter ``content_id``

Customization
-------------

The Routing bundles allows for several cutomization options, depending on
your specific needs:

* Your Route parameters can be easily manipulated using the exiting Enhancers
* Yuo can also add your own Enhancers to the Router logic.
* The ``DynamicRouter`` or its components can be extended to allow modifications
* You can implement your own Routers and add them to the ``ChainRouter``

.. note::

If you feel like your specific Enhancer or Router can be usefull to others,
get in touch with us and we'll try to include it in the bundle itself

You can generate urls for your content in three ways:
Symfony2 integration
--------------------

* Either pass an implementation of RouteObjectInterface as parameter ``route``
* Or pass a content object as parameter ``content``
* Or supply an implementation of ContentRepositoryInterface and the id of the content as parameter ``content_id``
Like mentioned before, this bundle was designed to only require certain parts
of Symfony2. However, if you wish to use it as part of your Symfony CMF project,
an integration bundle is also available. We strongly recommend that you take
a look at :doc:`../bundles/routing-extra`.

Authors
-------
Expand Down
31 changes: 31 additions & 0 deletions getting-started/overview.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
Overview
========

This guide will help you understand the basic parts of Symfony CMF and how
they work together to provide the default pages you can see when browsing
the Symfony CMF Standard Edition (SE) installation.

It assumes you have already installed Symfony CMF and have carefully
read the Symfony2 book.

AcmeMainBundle and SimpleCMSBundle
----------------------------------

Symfony CMF SE comes with a default AcmeMainBundle to help you get started,
in a similar way that Symfony2 has AcmeDemoBundle, providing you some
demo pages visible on your browser. However, AcmeMainBundle doesn't include
controllers or configuration files, like you probably would expect. It contains
little more than a twig file and `Fixtures <http://symfony.com/doc/current/bundles/DoctrineFixturesBundle/index.html>`_
data, that was loaded into your database during installation.

There are several bundles working together in order to turn the fixture data
into a browsable website. The overall, simplified process is:

- When a request is received, the Symfony CMF :doc:`routing`'s Dynamic Router is used to handle the incoming request.
- The Dynamic Router is able to match the requested URL with a specific ContentBundle's Content stored in the database.
- The retrieved content's information is used to determine which controller to pass it on to, and which template to use.
- As configured, the retrieved content is passed to ContentBundle's ContentController, which will handle it and render AcmeMainBundle's layout.html.twig.

Again, this is simplified view of a very simple CMS built on top of Symfony CMF.
To fully understand all the possibilities of the CMF, a carefull look into
each component is needed.
5 changes: 3 additions & 2 deletions index.rst
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Symfony CMF Documentation
Symfony CMF Documentation
=========================

Welcome to the official documentation of the `Symfony Content Management Framework`_.
Expand Down Expand Up @@ -52,6 +52,7 @@ Just started learning about the CMF? Want to know if the CMF fits your project?
:maxdepth: 1

getting-started/installing-symfony-cmf
getting-started/overview


Tutorials
Expand Down Expand Up @@ -104,7 +105,7 @@ Special solutions for special needs that go beyond standard usage.
cookbook/phpcr-odm-custom-documentclass-mapper
cookbook/using-a-custom-route-repository
cookbook/installing-cmf-sandbox

Components
----------

Expand Down