Commit c61908b3 authored by Fabien Potencier's avatar Fabien Potencier

Merge remote branch 'igorw/docs'

* igorw/docs:
  [docs] note that twig is not included
  [docs] add Extension suffix to extension titles
  [docs] some documentation for the UrlGeneratorExtension
  [docs] better examples for the extensions chapter
  [docs] remove reference to symfony_bridges in TwigExtension docs
  [docs] move extension documentation to sub-directory
  [docs] remove _exts
  [docs] more on routes and twig
  [docs] initial documentation draft
parents 880729b1 17f96105
import sys, os
from sphinx.highlighting import lexers
from pygments.lexers.web import PhpLexer
sys.path.append(os.path.abspath('_exts'))
extensions = ['configurationblock']
master_doc = 'index'
highlight_language = 'php'
project = u'Silex'
copyright = u'2010 Fabien Potencier'
version = '0'
release = '0.0.0'
lexers['php'] = PhpLexer(startinline=True)
Contributing
============
We are open to contributions to the Silex code. If you find
a bug or want to contribute an extension, just follow these
steps.
* Fork `the Silex repository <https://github.com/fabpot/Silex>`_
on github.
* Make your feature addition or bug fix.
* Add tests for it. This is important so we don't break it in a future version unintentionally.
* Send a pull request. Bonus points for topic branches.
.. note::
Any code you contribute must be licensed under the MIT
License.
Extensions
==========
Silex provides a common interface for extensions. These
define services on the application.
Loading extensions
------------------
In order to load and use an extension, you must register it
on the application. ::
use Acme\DatabaseExtension;
$app = new Application();
$app->register(new DatabaseExtension());
You can also provide some parameters as a second argument.
::
$app->register(new DatabaseExtension(), array(
'database.dsn' => 'mysql:host=localhost;dbname=myapp',
'database.user' => 'root',
'database.password' => 'secret_root_password',
));
Included extensions
-------------------
There are a few extensions that you get out of the box.
All of these are within the ``Silex\Extension`` namespace.
* :doc:`MonologExtension <extensions/monolog>`
* :doc:`TwigExtension <extensions/twig>`
* :doc:`UrlGeneratorExtension <extensions/url_generator>`
Creating an extension
---------------------
Extensions must implement the ``Silex\ExtensionInterface``.
::
interface ExtensionInterface
{
function register(Application $app);
}
This is very straight forward, just create a new class that
implements the ``register`` method. In this method you must
define services on the application which then may make use
of other services and parameters.
Here is an example of such an extension::
namespace Acme;
use Silex\ExtensionInterface;
class HelloExtension implements ExtensionInterface
{
public function register(Application $app)
{
$app['hello'] = $app->protect(function($name) use ($app) {
$default = ($app['hello.default_name']) ? $app['hello.default_name'] : '';
$name = $name ?: $default;
return "Hello $name";
});
}
}
This class provides a ``hello`` service which is a protected
closure. It takes a name argument and will return
``hello.default_name`` if no name is given. If the default
is also missing, it will use an empty string.
You can now use this extension as follows::
use Acme\HelloExtension;
$app = new Application();
$app->register(new HelloExtension(), array(
'hello.default_name' => 'Igor',
));
$app->get('/hello', function() use ($app) {
$name = $app['request']->get('name');
return $app['hello']($name);
});
In this example we are getting the ``name`` parameter from the
query string, so the request path would have to be ``/hello?name=Fabien``.
Class loading
~~~~~~~~~~~~~
Extensions are great for tying in external libraries as you
can see by looking at the ``MonologExtension`` and
``TwigExtension``. If the library is decent and follows the
`PSR-0 Naming Standard <http://groups.google.com/group/php-standards/web/psr-0-final-proposal>`_
or the PEAR Naming Convention, it is possible to autoload
classes using the ``UniversalClassLoader``.
As described in the *Services* chapter, there is an
*autoloader* service that you can use for this.
Here is an example of how to use it (based on `Buzz <https://github.com/kriswallsmith/Buzz>`_)::
namespace Acme;
use Silex\ExtensionInterface;
class BuzzExtension implements ExtensionInterface
{
public function register(Application $app)
{
$app['buzz'] = $app->share(function() { ... });
if (isset($app['buzz.class_path'])) {
$app['autoloader']->registerNamespace('Buzz', $app['buzz.class_path']);
}
}
}
This allows you to simply provide the class path as an
option when registering the extension::
$app->register(new BuzzExtension(), array(
'buzz.class_path' => __DIR__.'/vendor/buzz/lib',
));
.. note::
For libraries that do not use PHP 5.3 namespaces you can use ``registerPrefix``
instead of ``registerNamespace``, which will use an underscore as directory
delimiter.
Silex
=====
.. toctree::
:maxdepth: 2
monolog
twig
url_generator
MonologExtension
================
The *MonologExtension* provides a default logging mechanism
through Jordi Boggiano's `Monolog <https://github.com/Seldaek/monolog>`_
library.
It will log requests and errors and allow you to add debug
logging to your application, so you don't have to use
``var_dump`` so much anymore. You can use the grown-up
version called ``tail -f``.
Parameters
----------
* **monolog.logfile**: File where logs are written to.
* **monolog.class_path** (optional): Path to where the
Monolog library is located.
* **monolog.level** (optional): Level of logging defaults
to ``DEBUG``. Must be one of ``Logger::DEBUG``, ``Logger::INFO``,
``Logger::WARNING``, ``Logger::ERROR``. ``DEBUG`` will log
everything, ``INFO`` will log everything except ``DEBUG``,
etc.
* **monolog.name** (optional): Name of the monolog channel,
defaults to ``myapp``.
Services
--------
* **monolog**: The monolog logger instance.
Example usage::
$app['monolog']->addDebug('Testing the Monolog logging.');
* **monolog.configure**: Protected closure that takes the
logger as an argument. You can override it if you do not
want the default behavior.
Registering
-----------
Make sure you place a copy of *Monolog* in the ``vendor/monolog``
directory.
::
use Silex\Extension\MonologExtension;
$app->register(new MonologExtension(), array(
'monolog.logfile' => __DIR__.'/development.log',
'monolog.class_path' => __DIR__.'/vendor/monolog/src',
));
TwigExtension
=============
The *TwigExtension* provides integration with the `Twig
<http://www.twig-project.org/>`_ template engine.
Parameters
----------
* **twig.path**: Path to the directory containing twig template
files.
* **twig.templates** (optional): If this option is provided
you don't have to provide a ``twig.path``. It is an
associative array of template names to template contents.
Use this if you want to define your templates inline.
* **twig.options** (optional): An associative array of twig
options. Check out the twig documentation for more information.
* **twig.class_path** (optional): Path to where the Twig
library is located.
Services
--------
* **twig**: The ``Twig_Environment`` instance, you will only
need to use this.
* **twig.configure**: Protected closure that takes the twig
environment as an argument. You can use it to add more
custom globals.
* **twig.loader**: The loader for twig templates which uses
the ``twig.path`` and the ``twig.templates`` options. You
can also replace the loader completely.
Registering
-----------
Make sure you place a copy of *Twig* in the ``vendor/twig``
directory.
::
use Silex\Extension\TwigExtension;
$app->register(new TwigExtension(), array(
'twig.path' => __DIR__.'/views',
'twig.class_path' => __DIR__.'/vendor/twig/lib',
));
.. note::
Twig is not compiled into the ``silex.phar`` file. You have to
add your own copy of Twig to your application.
Usage
-----
The Twig extension provides a ``twig`` service.
::
$app->get('/hello/{name}', function($name) use ($app) {
return $app['twig']->render('hello.twig', array(
'name' => $name,
));
});
This will render a file named ``views/hello.twig``.
It also registers the application as a global named
``app``. So you can access any services from within your
view. For example to access ``$app['request']->getHost()``,
just put this in your template:
.. code-block:: jinja
{{ app.request.host }}
UrlGeneratorExtension
=====================
The *UrlGeneratorExtension* provides a service for generating
URLs for named routes.
Parameters
----------
None.
Services
--------
* **url_generator**: An instance of
``Symfony\Component\Routing\Generator\UrlGenerator``, using the
``RouteCollection`` that is provided through the ``routes`` service.
It has a ``generate`` method, which takes the route name as an argument,
followed by an array of route parameters.
Registering
-----------
::
use Silex\Extension\UrlGeneratorExtension;
$app->register(new UrlGeneratorExtension());
Usage
-----
The UrlGenerator extension provides a ``url_generator`` service.
::
$app->get('/', function() {
return 'welcome to the homepage';
})
->bind('homepage');
$app->get('/hello/{name}', function($name) {
return "Hello $name!";
})
->bind('hello');
$app->get('/navigation', function() use ($app) {
return '<a href="'.$app['url_generator']->generate('homepage').'">Home</a>'.
' | '.
'<a href="'.$app['url_generator']->generate('hello', array('name' => 'Igor')).'">Hello Igor</a>';
});
Silex
=====
.. toctree::
:maxdepth: 2
intro
usage
services
extensions
internals
contributing
Internals
=========
This chapter will tell you a bit about how Silex works
internally.
Silex
-----
Application
~~~~~~~~~~~
The application is the main interface to Silex. It
implements Symfony2's ``HttpKernelInterface``, so you can
pass a ``Request`` to the ``handle`` method and it will
return a ``Response``.
It extends the ``Pimple`` service container, allowing
for flexibility on the outside as well as the inside. you
could replace any service, and you are also able to read
them.
The application makes strong use of the ``EventDispatcher``
to hook into the Symfony2 HttpKernel events. This allows
fetching the ``Request``, converting string responses into
``Response`` objects and handling Exceptions. We also use it
to dispatch some custom events like before/after filters and
errors.
Controller
~~~~~~~~~~
The Symfony2 ``Route`` is actually quite powerful. Routes
can be named, which allows for URL generation. They can
also have requirements for the variable parts. In order
to allow settings these through a nice interface the
``match`` method (which is used by ``get``, ``post``, etc.)
returns an instance of the ``Controller``, which wraps
a route.
ControllerCollection
~~~~~~~~~~~~~~~~~~~~
One of the goals of exposing the ``RouteCollection`` was
to make it mutable, so extensions could add stuff to it.
The challenge here is the fact that routes know nothing
about their name. The name only has meaning in context
of the ``RouteCollection`` and cannot be changed.
To solve this challenge we came up with a staging area
for routes. The ``ControllerCollection`` holds the
controllers until ``flush`` is called, at which point
the routes are added to the ``RouteCollection``. Also,
the controllers are frozen. This means that they can
no longer be modified and will throw an Exception if
you try to do so.
Unfortunately no good way for flushing implicitly
could be found, which is why flushing is now always
explicit. The Application will flush, but if you want
to read the ``ControllerCollection`` before the
request takes place, you will have to call flush
first.
The ``Application`` provides a shortcut ``flush``
method for flushing the ``ControllerCollection``.
Symfony2
--------
Following Symfony2 components are used by Silex:
* **ClassLoader**: For autoloading classes.
* **HttpFoundation**: For ``Request`` and ``Response``.
* **HttpKernel**: Because we need a heart.
* **Routing**: For matching defined routes.
* **EventDispatcher**: For hooking into the HttpKernel.
Introduction
============
Silex is a PHP microframework for PHP 5.3. It is built on the shoulders
of Symfony2 and Pimple and also inspired by sinatra.
A microframework provides the guts for building simple single-file apps.
Silex aims to be:
* *Concise*: Silex exposes a intuitive and concise API that is fun to use.
* *Extensible*: Silex has an extension system based around the Pimple
micro service-container that makes it even easier to tie in third party
libraries.
* *Testable*: Silex uses Symfony2's HttpKernel which abstracts request and
response. This makes it very easy to test apps and the framework itself.
It also respects the HTTP specification and encourages its proper use.
In a nutshell, you define controllers and map them to routes, all in one
step.
Let's go! ::
require_once __DIR__.'/silex.phar';
$app = new Silex\Application();
$app->get('/hello/{name}', function($name) {
return "Hello $name";
});
$app->run();
All that is needed to get access to the Framework is to include
``silex.phar``. This phar (PHP Archive) file will take care of the rest.
Next we define a route to ``/hello/{name}`` that matches for ``GET``
requests. When the route matches, the function is executed and the return
value is sent back to the client.
Finally, the app is run. It's really that easy!
Installation
------------
Installing Silex is as easy as it can get. Download the [`silex.phar`][2] file
and you're done!
License
-------
Silex is licensed under the MIT license.
.. code-block:: text
Copyright (c) 2010 Fabien Potencier
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
Services
========
Silex is not only a microframework. It is also a micro service container.
It does this by extending `Pimple <https://github.com/fabpot/Pimple>`_
which provides service goodness in just 44 NCLOC.
Dependency Injection
--------------------
.. note::
You can skip this if you already know what Dependency Injection is.
Dependency Injection is a design pattern where you pass dependencies
to services instead of creating them from within the service or
relying on globals. This generally leads to code that is decoupled,
re-usable, flexible and testable.
Here is an example::
class JsonUserPersister
{
private $basePath;
public function __construct($basePath)
{
$this->basePath = $basePath;
}
public function persist(User $user)
{
$data = $user->getAttributes();
$json = json_encode($data);
$filename = $this->basePath.'/'.$user->id.'.json';
file_put_contents($filename, $json, LOCK_EX);
}
}
In this simple example the dependency is the ``basePath`` property.
It is passed to the constructor. This means you can create several
independent instances with different base paths. Of course
dependencies do not have to be simple strings. More often they are
in fact other services.
Container
~~~~~~~~~
A DI or service container is responsible for creating and storing
services. It can recursively create dependencies of the requested
services and inject them. It does so lazily, which means a service
is only created when you actually need it.
Most containers are quite complex and are configured through XML
or YAML files.
Pimple is different.
Pimple
------
Pimple is probably the simplest service container out there. It
makes strong use of closures implements the ArrayAccess interface.
We will start off by creating a new instance of Pimple -- and
because ``Silex\Application`` extends ``Pimple`` all of this
applies to Silex as well. ::
$container = new Pimple();
or ::
use Silex\Application;
$app = new Application();
Parameters
~~~~~~~~~~
You can set parameters (which are usually strings) by setting
an array key on the container::
$app['some_parameter'] = 'value';
The array key can be anything, by convention periods are
used for namespacing. ::
$app['asset.host'] = 'http://cdn.mysite.com/';
Reading parameter values is possible with the same
syntax. ::
echo $app['some_parameter'];
Service definitions
~~~~~~~~~~~~~~~~~~~
Defining services is no different than defining parameters.
You just set an array key on the container to be a closure.
The difference is, when you retrieve the service, the
closure is executed. This allows for lazy service creation.
::
$app['some_service'] = function() {
return new Service();
};
And to retrieve the service, use::
$service = $app['some_service'];
Every time you call ``$app['some_service']``, a new instance
of the service is created.
Shared services
~~~~~~~~~~~~~~~
You may want to use the same instance of a service across all
of your code. In order to do that you can make a *shared*
service. ::
$app['some_service'] = $app->share(function() {
return new Service();
});
This will create the service on first invocation, and then
return the existing instance on any subsequent access.
Access container from closure
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In many cases you will want to access the service container
from within a service definition closure. For example when
fetching services the current service depends on.
Because of this, the container is passed to the closure as
an argument. ::
$app['some_service'] = function($app) {
return new Service($app['some_other_service'], $app['some_service.config']);
};
Here you can see an example of Dependency Injection.
``some_service`` depends on ``some_other_service`` and
takes ``some_service.config`` as configuration options.
The dependency is only created when ``some_service`` is
accessed, and it is possible to replace either of the
dependencies by simply overriding those definitions.
.. note::
This also works for shared services.
Protected closures
~~~~~~~~~~~~~~~~~~
Because the container sees closures as factories for
services, it will always execute them when reading them.
In some cases you will however want to store a closure
as a parameter, so that you can fetch it and execute it
yourself -- with your own arguments.
This is why Pimple allows you to protect your closures
from being executed, by using the ``protect`` method.
::
$app['closure_parameter'] = $app->protect(function($a, $b) {
return $a + $b;
});
// will not execute the closure
$add = $app['closure_parameter'];
// calling it now
echo $add(2, 3);
Note that protected closures do not get access to
the container.
Predefined services
-------------------
Silex defines a range of services which can be used
or replaced. You probably don't want to mess with most
of them.
* **request**: Contains the current request object,
which is an instance of ``Symfony\Component\HttpFoundation\Request``.
It gives you access to ``GET``, ``POST`` parameters
and lots more!
Example usage::
$id = $app['request']->get('id');
* **autoloader**: This service provides you with a
``Symfony\Component\ClassLoader\UniversalClassLoader``
that is already registered. You can register prefixes
and namespaces on it.
Example usage, autoloads Twig classes::
$app['autoloader']->registerPrefix('Twig_', $app['twig.class_path']);
* **routes**: The ``Symfony\Component\Routing\RouteCollection``
that is used internally. You can add, modify, read
routes.
* **controllers**: The ``Silex\ControllerCollection``
that is used internally. Check the *Internals*
chapter for more information.
* **dispatcher**: The ``Symfony\Component\EventDispatcher\EventDispatcher``
that is used internally. It is the core of the Symfony2
system and is used quite a bit by Silex.
* **resolver**: The ``Symfony\Component\HttpKernel\Controller\ControllerResolver``
that is used internally. It takes care of executing the
controller with the right arguments.
* **kernel**: The ``Symfony\Component\HttpKernel\HttpKernel``
that is used internally. The HttpKernel is the heart of
Symfony2, it takes a Request as input and returns a
Response as output.
.. note::
All of these Silex core services are shared.
Usage
=====
This chapter describes how to use Silex.
Bootstrap
---------
To include the Silex all you need to do is require the ``silex.phar``
file and create an instance of ``Silex\Application``. After your
controller definitions, call the ``run`` method on your application.
::
require __DIR__.'/silex.phar';
use Silex\Application;
$app = new Application();
// definitions
$app->run();
The use statement aliases ``Silex\Application`` to ``Application``.
One other thing you have to do is configure your web server. If you
are using apache you can use a ``.htaccess`` file for this.
.. code-block:: text
<IfModule mod_rewrite.c>
RewriteEngine On
#RewriteBase /path/to/app
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php [QSA,L]
</IfModule>
.. note::
If your site is not at the webroot level you will have to uncomment the
``RewriteBase`` statement and adjust the path to point to your directory,
relative from the webroot.
Routing
-------
In Silex you define a route and the controller that is called when that
route is matched
A route pattern consists of:
* *Pattern*: The route pattern defines a path that points to a resource.
The pattern can include variable parts and you are able to set
RegExp requirements for them.
* *Method*: One of the following HTTP methods: ``GET``, ``POST``, ``PUT``
``DELETE``. This describes the interaction with the resource. Commonly
only ``GET`` and ``POST`` are used, but it is possible to use the
others as well.
The controller can be any PHP callable, so either of::
'functionName'
array('Class', 'staticMethodName')
array($object, 'methodName')
But the encouraged way of defining controllers is a closure is this::
function() {
// do something
}
Closures are anonymous functions that may import state from outside
of their definition. This is different from globals, because the outer
state does not have to be global. For instance, you could define a
closure in a function and import local variables of that function.
.. note::
Closures that do not import scope are referred to as lambdas.
Because in PHP all anonymous functions are instances of the
``Closure`` class, we will not make a distinction here.
The return value of the closure becomes the content of the page.
Example GET route
~~~~~~~~~~~~~~~~~
Here is an example definition of a ``GET`` route::
$blogPosts = array(
1 => array(
'date' => '2011-03-29',
'author' => 'igorw',
'title' => 'Using Silex',
'body' => '...',
),
);
$app->get('/blog', function() use ($blogPosts) {
$output = '';
foreach ($blogPosts as $post) {
$output .= $post['title'];
$output .= '<br />';
}
return $output;
});
Visiting ``/blog`` will return a list of blog post titles. The ``use``
statement means something different in this context. It tells the
closure to import the $blogPosts variable from the outer scope. This
allows you to use it from within the closure.
Dynamic routing
~~~~~~~~~~~~~~~
Now, you can create another controller for viewing individual blog
posts::
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
$app->get('/blog/show/{id}', function($id) use ($blogPosts) {
if (!isset($blogPosts[$id])) {
throw new NotFoundHttpException();
}
$post = $blogPosts[$id];
return "<h1>{$post['title']}</h1>".
"<p>{$post['body']}</p>";
});
This route definition has a variable ``{id}`` part which is passed
to the closure.
As you can see, we are throwing a ``NotFoundHttpException`` if the
post does not exist. We will see how to handle this later on.
Example POST route
~~~~~~~~~~~~~~~~~~
POST routes signify the creation of a resource. An example for this is a
feedback form. We will use `Swift Mailer
<http://swiftmailer.org/>`_ and assume a copy of it to be present in the
``vendor/swiftmailer`` directory.
::
require_once __DIR__.'/vendor/swiftmailer/lib/swift_required.php';
use Symfony\Component\HttpFoundation\Response;
$app->post('/feedback', function() use ($app) {
$request = $app['request'];
$message = \Swift_Message::newInstance()
->setSubject('[YourSite] Feedback')
->setFrom(array('noreply@yoursite.com'))
->setTo(array('feedback@yoursite.com'))
->setBody($request->get('message'));
$transport = \Swift_MailTransport::newInstance();
$mailer = \Swift_Mailer::newInstance($transport);
$mailer->send($message);
return new Response('Thank you for your feedback!', 201);
});
It is pretty straight forward. We include the Swift Mailer library,
set up a message and send that message.
The current ``request`` service is retrieved using the array key syntax.
You can find more information about services in the *Services* chapter.
The request is an instance of ``Symfony\Component\HttpFoundation\Request``,
so you can fetch variables using the request's ``get`` method.
Instead of returning a string we are returning an instance of
``Symfony\Component\HttpFoundation\Response``. This allows setting an HTTP
status code, in this case it is set to ``201 Created``.
.. note::
Silex always uses ``Response`` internally, it converts strings to
responses with status code ``200 Ok``.
Other methods
~~~~~~~~~~~~~
You can create controllers for most HTTP methods. Just call one of these
methods on your application: ``get``, ``post``, ``put``, ``delete``. You
can also call ``match``, which will match all methods.
::
$app->put('/blog', function() {
...
});
.. note::
The order in which the routes are defined is significant. The first
matching route will be used, so place more generic routes at the bottom.
Route variables
~~~~~~~~~~~~~~~
As has been before you can define variable parts in a route like this::
$app->get('/blog/show/{id}', function($id) {
...
});
It is also possible to have more than one variable part, just make sure the
closure arguments match the names of the variable parts.
::
$app->get('/blog/show/{postId}/{commentId}', function($postId, $commentId) {
...
});
While it's not suggested, you could also do this (note the switched arguments)::
$app->get('/blog/show/{postId}/{commentId}', function($commentId, $postId) {
...
});
In some cases you may want to only match certain expressions. You can define
requirements using regular expressions by calling ``assert`` on the
``Controller`` object, which is returned by the routing methods.
The following will make sure the ``id`` argument is numeric, since ``\d+``
matches any amount of digits::
$app->get('/blog/show/{id}', function($id) {
...
})
->assert('id', '\d+');
You can also chain these calls::
$app->get('/blog/show/{postId}/{commentId}', function($postId, $commentId) {
...
})
->assert('postId', '\d+')
->assert('commentId', '\d+');
Named routes
~~~~~~~~~~~~~~~
Certain extensions (such as ``UrlGenerator``) can make use of named routes.
By default Silex will generate a route name for you, that cannot really be
used. You can give a route a name by calling ``bind`` on the ``Controller``
object that is returned by the routing methods.
::
$app->get('/', function() {
...
})
->bind('homepage');
$app->get('/blog/show/{id}', function($id) {
...
})
->bind('blog_post');
.. note::
It only makes sense to name routes if you use extensions that make use
of the ``RouteCollection``.
Before and after filters
------------------------
Silex allows you to run code before and after every request. This happens
through before and after filters. All you need to do is pass a closure::
$app->before(function() {
// set up
});
$app->after(function() {
// tear down
});
Error handlers
--------------
If some part of your code throws an exception you will want to display
some kind of error page to the user. This is what error handlers do. You
can also use them to do additional things, such as logging.
To register an error handler, pass a closure to the ``error`` method
which takes an ``Exception`` argument and returns a response::
use Symfony\Component\HttpFoundation\Response;
$app->error(function(\Exception $e) {
return new Response('We are sorry, but something went terribly wrong.', 500);
});
You can also check for specific errors by using ``instanceof``, and handle
them differently::
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\BaseHttpException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
$app->error(function(\Exception $e) {
if ($e instanceof NotFoundHttpException) {
return new Response('The requested page could not be found.', 404);
}
$code = ($e instanceof BaseHttpException) ? $e->getStatusCode() : 500;
return new Response('We are sorry, but something went terribly wrong.', $code);
});
If you want to set up logging you can use a separate error handler for that.
Just make sure you register it before the response error handlers, because
once a response is returned, the following handlers are ignored.
.. note::
Silex ships with an extension for `Monolog <https://github.com/Seldaek/monolog>`_
which handles logging of errors. Check out the *Extensions* chapter
for details.
Redirects
---------
You can redirect to another page by returning a redirect response, which
you can create by calling the ``redirect`` method::
$app->get('/', function() use ($app) {
return $app->redirect('/hello');
});
This will redirect from ``/`` to ``/hello``.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment