Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Sign in
Toggle navigation
S
Silex
Project overview
Project overview
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Commits
Open sidebar
common
Silex
Commits
7a376eb3
Commit
7a376eb3
authored
May 26, 2012
by
Fabien Potencier
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
fixed markup in the docs
parent
7c496d60
Changes
18
Hide whitespace changes
Inline
Side-by-side
Showing
18 changed files
with
311 additions
and
350 deletions
+311
-350
doc/cookbook/form_no_csrf.rst
doc/cookbook/form_no_csrf.rst
+17
-16
doc/cookbook/index.rst
doc/cookbook/index.rst
+4
-2
doc/cookbook/json_request_body.rst
doc/cookbook/json_request_body.rst
+8
-12
doc/cookbook/session_storage.rst
doc/cookbook/session_storage.rst
+5
-6
doc/cookbook/validator_yaml.rst
doc/cookbook/validator_yaml.rst
+1
-3
doc/internals.rst
doc/internals.rst
+33
-43
doc/intro.rst
doc/intro.rst
+14
-16
doc/providers.rst
doc/providers.rst
+19
-24
doc/providers/monolog.rst
doc/providers/monolog.rst
+10
-15
doc/providers/session.rst
doc/providers/session.rst
+10
-9
doc/providers/swiftmailer.rst
doc/providers/swiftmailer.rst
+7
-10
doc/providers/symfony_bridges.rst
doc/providers/symfony_bridges.rst
+20
-17
doc/providers/translation.rst
doc/providers/translation.rst
+4
-2
doc/providers/twig.rst
doc/providers/twig.rst
+3
-3
doc/providers/url_generator.rst
doc/providers/url_generator.rst
+5
-5
doc/services.rst
doc/services.rst
+69
-82
doc/testing.rst
doc/testing.rst
+22
-18
doc/usage.rst
doc/usage.rst
+60
-67
No files found.
doc/cookbook/form_no_csrf.rst
View file @
7a376eb3
...
...
@@ -4,31 +4,32 @@ Disable CSRF Protection on a form using the FormExtension
The *FormExtension* provides a service for building form in your application
with the Symfony2 Form component. By default, the *FormExtension* uses the
CSRF Protection avoiding Cross-site request forgery, a method by which a
malicious user attempts to make your legitimate users unknowingly submit
data
that they don't intend to submit.
malicious user attempts to make your legitimate users unknowingly submit
data
that they don't intend to submit.
You can find more details about CSRF Protection and CSRF token in the `Symfony2 Book:
<http://symfony.com/doc/current/book/forms.html#csrf-protection>`
You can find more details about CSRF Protection and CSRF token in the
`Symfony2 Book
<http://symfony.com/doc/current/book/forms.html#csrf-protection>`_.
In some cases (for example, when embedding a form in an html email) you might want
not to use this protection. The easiest way to avoid this is to understand that it
is possible to give specific options to your form builder through the `createBuilder()` function.
In some cases (for example, when embedding a form in an html email) you might
want not to use this protection. The easiest way to avoid this is to
understand that it is possible to give specific options to your form builder
through the ``createBuilder()`` function.
Example
-------
::
.. code-block:: php
$form = $app['form.factory']->createBuilder('form', null, array('csrf_protection' => false));
That's it, your form could be submited from everywhere without CSRF Protection.
Going further
-------------
Going further..
---------------
This specific example showed how to change the `csrf_protection` in the `$options`
parameter of the `createBuilder()` function. More of them could be passed through
this parameter, it is as simple as using the Symfony2 `getDefaultOptions()` method
in your form classes. `See more here
<http://symfony.com/doc/current/book/forms.html#book-form-creating-form-classes>`
This specific example showed how to change the ``csrf_protection`` in the
``$options`` parameter of the ``createBuilder()`` function. More of them could
be passed through this parameter, it is as simple as using the Symfony2
``getDefaultOptions()`` method in your form classes. `See more here
<http://symfony.com/doc/current/book/forms.html#book-form-creating-form-classes>`_.
doc/cookbook/index.rst
View file @
7a376eb3
...
...
@@ -22,8 +22,10 @@ Recipes
* :doc:`Translating Validation Messages<translating_validation_messages>`.
* :doc:`How to use PdoSessionStorage to store sessions in the database <session_storage>`.
* :doc:`How to use PdoSessionStorage to store sessions in the database
<session_storage>`.
* :doc:`How to disable the CSRF Protection on a form using the FormExtension <form_no_csrf>`.
* :doc:`How to disable the CSRF Protection on a form using the FormExtension
<form_no_csrf>`.
* :doc:`How to use YAML to configure validation <validator_yaml>`.
doc/cookbook/json_request_body.rst
View file @
7a376eb3
...
...
@@ -16,9 +16,9 @@ Request
~~~~~~~
In the request we send the data for the blog post as a JSON object. We also
indicate that using the ``Content-Type`` header
.
indicate that using the ``Content-Type`` header
:
::
.. code-block:: text
POST /blog/posts
Accept: application/json
...
...
@@ -32,9 +32,9 @@ Response
The server responds with a 201 status code, telling us that the post was
created. It tells us the ``Content-Type`` of the response, which is also
JSON
.
JSON
:
::
.. code-block:: text
HTTP/1.1 201 Created
Content-Type: application/json
...
...
@@ -51,9 +51,7 @@ begins with ``application/json``. Since we want to do this for every request,
the easiest solution is to use a before filter.
We simply use ``json_decode`` to parse the content of the request and then
replace the request data on the ``$request`` object.
::
replace the request data on the ``$request`` object:
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\ParameterBag;
...
...
@@ -69,9 +67,7 @@ Controller implementation
-------------------------
Our controller will create a new blog post from the data provided and will
return the post object, including its ``id``, as JSON.
::
return the post object, including its ``id``, as JSON:
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
...
...
@@ -91,9 +87,9 @@ Manual testing
--------------
In order to manually test our API, we can use the ``curl`` command line
utility, which allows sending HTTP requests
.
utility, which allows sending HTTP requests
:
::
.. code-block:: bash
$ curl http://blog.lo/blog/posts -d '{"title":"Hello World!","body":"This is my first post!"}' -H 'Content-Type: application/json'
{"id":"1","title":"Hello World!","body":"This is my first post!"}
doc/cookbook/session_storage.rst
View file @
7a376eb3
...
...
@@ -7,15 +7,14 @@ medium to large websites use a database to store sessions instead of files,
because databases are easier to use and scale in a multi-webserver
environment.
Symfony2's ``NativeSessionStorage`` has multiple storage handlers and one of them uses PDO to
store sessions, ``PdoSessionHandler``.
To use it, replace the ``session.storage.handler`` service in your application like
explained below.
Symfony2's ``NativeSessionStorage`` has multiple storage handlers and one of
them uses PDO to store sessions, ``PdoSessionHandler``. To use it, replace the
``session.storage.handler`` service in your application like explained below.
Example
-------
::
.. code-block:: php
use Symfony\Component\HttpFoundation\Session\Storage\Handler\PdoSessionHandler;
...
...
@@ -59,4 +58,4 @@ PdoSessionStorage needs a database table with 3 columns:
You can find examples of SQL statements to create the session table in the
`Symfony2 cookbook
<http://symfony.com/doc/current/cookbook/configuration/pdo_session_storage.html>`
<http://symfony.com/doc/current/cookbook/configuration/pdo_session_storage.html>`
_
doc/cookbook/validator_yaml.rst
View file @
7a376eb3
...
...
@@ -15,9 +15,7 @@ your ``composer.json`` file:
}
Next, you need to tell the Validation Service that you are not using
``StaticMethodLoader`` to load your class metadata but a YAML file:
.. code-block:: php
``StaticMethodLoader`` to load your class metadata but a YAML file::
$app->register(new ValidatorServiceProvider());
...
...
doc/internals.rst
View file @
7a376eb3
...
...
@@ -10,68 +10,59 @@ Silex
Application
~~~~~~~~~~~
The application is the main interface to Silex. It
implements Symfony2's
`HttpKernelInterface
The application is the main interface to Silex. It
implements Symfony2's
`HttpKernelInterface
<http://api.symfony.com/master/Symfony/Component/HttpKernel/HttpKernelInterface.html>`_,
so you can pass a `Request
<http://api.symfony.com/master/Symfony/Component/HttpFoundation/Request.html>`_
to the ``handle`` method and it will return a `Response
<http://api.symfony.com/master/Symfony/Component/HttpFoundation/Response.html>`_.
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.
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
<http://api.symfony.com/master/Symfony/Component/EventDispatcher/EventDispatcher.html>`_
to hook into the Symfony2 `HttpKernel
<http://api.symfony.com/master/Symfony/Component/HttpKernel/HttpKernel.html>`_ 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.
<http://api.symfony.com/master/Symfony/Component/HttpKernel/HttpKernel.html>`_
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
<http://api.symfony.com/master/Symfony/Component/Routing/Route.html>`_
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.
<http://api.symfony.com/master/Symfony/Component/Routing/Route.html>`_ 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
<http://api.symfony.com/master/Symfony/Component/Routing/RouteCollection.html>`_
was to make it mutable, so providers 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 then 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
yourself.
The ``Application`` provides a shortcut ``flush``
method for flushing the ``ControllerCollection``.
was to make it mutable, so providers 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 then 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 yourself.
The ``Application`` provides a shortcut ``flush`` method for flushing the
``ControllerCollection``.
Symfony2
--------
...
...
@@ -88,5 +79,4 @@ Following Symfony2 components are used by Silex:
* **EventDispatcher**: For hooking into the HttpKernel.
For more information, `check out the Symfony website
<http://symfony.com/>`_.
For more information, `check out the Symfony website <http://symfony.com/>`_.
doc/intro.rst
View file @
7a376eb3
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.
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:
A microframework provides the guts for building simple single-file apps.
Silex
aims to be:
* *Concise*: Silex exposes an 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.
* *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.
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.
In a nutshell, you define controllers and map them to routes, all in one step.
**Let's go!**::
...
...
@@ -37,12 +35,12 @@ step.
All that is needed to get access to the Framework is to include the
autoloader.
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.
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. Visit ``/hello/world`` to see the result.
It's really
that easy!
Finally, the app is run. Visit ``/hello/world`` to see the result.
It's really
that easy!
Installing Silex is as easy as it can get. Download the `silex.zip`_ file,
extract it, and you're done!
...
...
doc/providers.rst
View file @
7a376eb3
...
...
@@ -31,26 +31,23 @@ will be set **before** the provider is registered::
Conventions
~~~~~~~~~~~
You need to watch out in what order you do certain things when
interacting
with providers. Just keep to these rules:
You need to watch out in what order you do certain things when
interacting
with providers. Just keep to these rules:
* Overriding existing services must occur **after** the
provider is
registered.
* Overriding existing services must occur **after** the
provider is
registered.
*Reason: If the services already exist, the provider
will overwrite it.*
*Reason: If the services already exist, the provider will overwrite it.*
* You can set parameters any time before the service is
accessed.
* You can set parameters any time before the service is accessed.
Make sure to stick to this behavior when creating your
own providers.
Make sure to stick to this behavior when creating your own providers.
Included providers
~~~~~~~~~~~~~~~~~~
There are a few provider that you get out of the box.
All of these are within the ``Silex\Provider`` namespace.
There are a few provider that you get out of the box.
All of these are within
the ``Silex\Provider`` namespace:
* :doc:`DoctrineServiceProvider <providers/doctrine>`
* :doc:`MonologServiceProvider <providers/monolog>`
...
...
@@ -66,8 +63,8 @@ All of these are within the ``Silex\Provider`` namespace.
Third party providers
~~~~~~~~~~~~~~~~~~~~~
Some service providers are developed by the community. Those
third-party providers are listed on `Silex' repository wiki
Some service providers are developed by the community. Those
third-party
providers are listed on `Silex' repository wiki
<https://github.com/fabpot/Silex/wiki/Third-Party-ServiceProviders>`_.
You are encouraged to share yours.
...
...
@@ -82,10 +79,9 @@ Providers must implement the ``Silex\ServiceProviderInterface``::
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.
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 a provider::
...
...
@@ -107,10 +103,9 @@ Here is an example of such a provider::
}
}
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.
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 provider as follows::
...
...
@@ -126,8 +121,8 @@ You can now use this provider as follows::
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``.
In this example we are getting the ``name`` parameter from the
query string,
so the request path would have to be ``/hello?name=Fabien``.
Controllers providers
---------------------
...
...
doc/providers/monolog.rst
View file @
7a376eb3
MonologServiceProvider
======================
The *MonologServiceProvider* provides a default logging mechanism
through Jordi Boggiano's `Monolog <https://github.com/Seldaek/monolog>`_
library.
The *MonologServiceProvider* 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``.
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
----------
...
...
@@ -33,9 +31,8 @@ Services
$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.
* **monolog.configure**: Protected closure that takes the logger as an
argument. You can override it if you do not want the default behavior.
Registering
-----------
...
...
@@ -60,11 +57,9 @@ Registering
Usage
-----
The MonologServiceProvider provides a ``monolog`` service. You can use
it to add log entries for any logging level through ``addDebug()``,
``addInfo()``, ``addWarning()`` and ``addError()``.
::
The MonologServiceProvider provides a ``monolog`` service. You can use it to
add log entries for any logging level through ``addDebug()``, ``addInfo()``,
``addWarning()`` and ``addError()``:
use Symfony\Component\HttpFoundation\Response;
...
...
doc/providers/session.rst
View file @
7a376eb3
...
...
@@ -24,8 +24,8 @@ Parameters
* **secure**: Cookie secure (HTTPS)
* **httponly**: Whether the cookie is http only
However, all of these are optional. Sessions last as long as the browser
is
open. To override this, set the ``lifetime`` option.
However, all of these are optional. Sessions last as long as the browser
is
open. To override this, set the ``lifetime`` option.
Services
--------
...
...
@@ -33,11 +33,12 @@ Services
* **session**: An instance of Symfony2's `Session
<http://api.symfony.com/master/Symfony/Component/HttpFoundation/Session/Session.html>`_.
* **session.storage**: A service that is used for persistence of the
session data. Defaults to a ``NativeSessionStorage``
* **session.storage.handler**: A service that is used by the ``session.storage``
for data access. Defaults to a ``NativeFileSessionHandler`` storage handler.
* **session.storage**: A service that is used for persistence of the session
data. Defaults to a ``NativeSessionStorage``.
* **session.storage.handler**: A service that is used by the
``session.storage`` for data access. Defaults to a
``NativeFileSessionHandler`` storage handler.
Registering
-----------
...
...
@@ -49,8 +50,8 @@ Registering
Usage
-----
The Session provider provides a ``session`` service. Here is an
example that
authenticates a user and creates a session for him::
The Session provider provides a ``session`` service. Here is an
example that
authenticates a user and creates a session for him::
use Symfony\Component\HttpFoundation\Response;
...
...
doc/providers/swiftmailer.rst
View file @
7a376eb3
SwiftmailerServiceProvider
==========================
The *SwiftmailerServiceProvider* provides a service for sending
email through the `Swift Mailer <http://swiftmailer.org>`_
library.
The *SwiftmailerServiceProvider* provides a service for sending email through
the `Swift Mailer <http://swiftmailer.org>`_ library.
You can use the ``mailer`` service to send messages easily.
By default, it
will attempt to send emails through SMTP.
You can use the ``mailer`` service to send messages easily.
By default, it
will attempt to send emails through SMTP.
Parameters
----------
* **swiftmailer.options**: An array of options for the default
SMTP-based
configuration.
* **swiftmailer.options**: An array of options for the default
SMTP-based
configuration.
The following options can be set:
...
...
@@ -75,9 +74,7 @@ Registering
Usage
-----
The Swiftmailer provider provides a ``mailer`` service.
::
The Swiftmailer provider provides a ``mailer`` service:
$app->post('/feedback', function () use ($app) {
$request = $app['request'];
...
...
doc/providers/symfony_bridges.rst
View file @
7a376eb3
...
...
@@ -12,23 +12,26 @@ none
Twig
----
When the ``SymfonyBridgesServiceProvider`` is enabled, the ``TwigServiceProvider`` will
provide you with the following additional capabilities:
* **UrlGeneratorServiceProvider**: If you are using the ``UrlGeneratorServiceProvider``,
you will get ``path`` and ``url`` helpers for Twig. You can find more
information in the
`Symfony2 Routing documentation <http://symfony.com/doc/current/book/routing.html#generating-urls-from-a-template>`_.
* **TranslationServiceProvider**: If you are using the ``TranslationServiceProvider``,
you will get ``trans`` and ``transchoice`` helpers for translation in
Twig templates. You can find more information in the
`Symfony2 Translation documentation <http://symfony.com/doc/current/book/translation.html#twig-templates>`_.
* **FormServiceProvider**: If you are using the ``FormServiceProvider``,
you will get a set of helpers for working with forms in templates.
You can find more information in the
`Symfony2 Forms reference <http://symfony.com/doc/current/reference/forms/twig_reference.html>`_.
When the ``SymfonyBridgesServiceProvider`` is enabled, the
``TwigServiceProvider`` will provide you with the following additional
capabilities:
* **UrlGeneratorServiceProvider**: If you are using the
``UrlGeneratorServiceProvider``, you will get ``path`` and ``url`` helpers
for Twig. You can find more information in the `Symfony2 Routing
documentation
<http://symfony.com/doc/current/book/routing.html#generating-urls-from-a-template>`_.
* **TranslationServiceProvider**: If you are using the
``TranslationServiceProvider``, you will get ``trans`` and ``transchoice``
helpers for translation in Twig templates. You can find more information in
the `Symfony2 Translation documentation
<http://symfony.com/doc/current/book/translation.html#twig-templates>`_.
* **FormServiceProvider**: If you are using the ``FormServiceProvider``, you
will get a set of helpers for working with forms in templates. You can find
more information in the `Symfony2 Forms reference
<http://symfony.com/doc/current/reference/forms/twig_reference.html>`_.
Registering
-----------
...
...
doc/providers/translation.rst
View file @
7a376eb3
...
...
@@ -24,7 +24,8 @@ Services
that is used for translation.
* **translator.loader**: An instance of an implementation of the translation
`LoaderInterface <http://api.symfony.com/master/Symfony/Component/Translation/Loader/LoaderInterface.html>`_,
`LoaderInterface
<http://api.symfony.com/master/Symfony/Component/Translation/Loader/LoaderInterface.html>`_,
defaults to an `ArrayLoader
<http://api.symfony.com/master/Symfony/Component/Translation/Loader/ArrayLoader.html>`_.
...
...
@@ -171,7 +172,8 @@ That's it.
Accessing translations in Twig templates
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Once loaded, the translation service provider is available from within Twig templates:
Once loaded, the translation service provider is available from within Twig
templates:
.. code-block:: jinja
...
...
doc/providers/twig.rst
View file @
7a376eb3
...
...
@@ -29,9 +29,9 @@ Services
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
c
an also replace the loader c
ompletely.
* **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
-----------
...
...
doc/providers/url_generator.rst
View file @
7a376eb3
UrlGeneratorServiceProvider
===========================
The *UrlGeneratorServiceProvider* provides a service for generating
URLs for
named routes.
The *UrlGeneratorServiceProvider* provides a service for generating
URLs for
named routes.
Parameters
----------
...
...
@@ -16,9 +16,9 @@ Services
<http://api.symfony.com/master/Symfony/Component/Routing/Generator/UrlGenerator.html>`_,
using the `RouteCollection
<http://api.symfony.com/master/Symfony/Component/Routing/RouteCollection.html>`_
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.
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
-----------
...
...
doc/services.rst
View file @
7a376eb3
...
...
@@ -12,13 +12,13 @@ Dependency Injection
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.
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 of a class that takes a ``User`` object and stores
it as a
file in JSON format::
Here is an example of a class that takes a ``User`` object and stores
it as a
file in JSON format::
class JsonUserPersister
{
...
...
@@ -38,34 +38,33 @@ it as a file in JSON format::
}
}
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.
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 DIC 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.
A DIC 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.
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 and implements the ArrayAccess interface.
Pimple is probably the simplest service container out there. It
makes strong
use of closures and implements the ArrayAccess interface.
We will start off by creating a new instance of Pimple -- and
because ``Silex\Application`` extends ``Pimple`` all of thi
s
applies to Silex as
well::
We will start off by creating a new instance of Pimple -- and
because
``Silex\Application`` extends ``Pimple`` all of this applies to Silex a
s
well::
$container = new Pimple();
...
...
@@ -76,28 +75,26 @@ or::
Parameters
~~~~~~~~~~
You can set parameters (which are usually strings) by setting
an array key on
the container::
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::
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::
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.
However, when you retrieve the service, the closure is executed.
This allows for lazy service creation::
Defining services is no different than defining parameters. You just set an
array key on the container to be a closure. However, when you retrieve the
service, the closure is executed. This allows for lazy service creation::
$app['some_service'] = function () {
return new Service();
...
...
@@ -107,43 +104,40 @@ 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.
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::
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.
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.
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::
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.
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::
...
...
@@ -152,15 +146,14 @@ dependencies by simply overriding those definitions.
Protected closures
~~~~~~~~~~~~~~~~~~
Because the container sees closures as factories for
services, it will always
execute them when reading them.
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.
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::
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;
...
...
@@ -172,56 +165,50 @@ from being executed, by using the ``protect`` method::
// calling it now
echo $add(2, 3);
Note that protected closures do not get access to
the container.
Note that protected closures do not get access to the container.
Core services
-------------
Silex defines a range of services which can be used
or replaced. You probably don't want to mess with most
of them.
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
`Request
* **request**: Contains the current request object,
which is an instance of
`Request
<http://api.symfony.com/master/Symfony/Component/HttpFoundation/Request.html>`_.
It gives you access to ``GET``, ``POST`` parameters
and lots more!
It gives you access to ``GET``, ``POST`` parameters and lots more!
Example usage::
$id = $app['request']->get('id');
This is only available when a request is being served, you can only access
it
from within a controller, before filter, after filter or error handler.
This is only available when a request is being served, you can only access
it
from within a controller, before filter, after filter or error handler.
* **routes**: The `RouteCollection
<http://api.symfony.com/master/Symfony/Component/Routing/RouteCollection.html>`_
that is used internally. You can add, modify, read
routes.
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.
* **controllers**: The ``Silex\ControllerCollection`` that is used internally.
Check the *Internals* chapter for more information.
* **dispatcher**: The `EventDispatcher
<http://api.symfony.com/master/Symfony/Component/EventDispatcher/EventDispatcher.html>`_
that is used internally. It is the core of the Symfony2
system and is used
quite a bit by Silex.
that is used internally. It is the core of the Symfony2
system and is used
quite a bit by Silex.
* **resolver**: The `ControllerResolver
<http://api.symfony.com/master/Symfony/Component/HttpKernel/Controller/ControllerResolver.html>`_
that is used internally. It takes care of executing the
controller with the
right arguments.
that is used internally. It takes care of executing the
controller with the
right arguments.
* **kernel**: The `HttpKernel
<http://api.symfony.com/master/Symfony/Component/HttpKernel/HttpKernel.html>`_
that is used internally. The HttpKernel is the heart of
Symfony2, it takes a Request as input and returns a
Response as output.
that is used internally. The HttpKernel is the heart of Symfony2, it takes a
Request as input and returns a Response as output.
* **request_context**: The request context is a simplified representation
of
the request that is used by the Router and the UrlGenerator.
* **request_context**: The request context is a simplified representation
of
the request that is used by the Router and the UrlGenerator.
* **exception_handler**: The Exception handler is the default handler that is
used when you don't register one via the `error()` method or if your handler
...
...
doc/testing.rst
View file @
7a376eb3
...
...
@@ -3,30 +3,32 @@ Testing
Because Silex is built on top of Symfony2, it is very easy to write functional
tests for your application. Functional tests are automated software tests that
ensure that your code is working correctly. They go through the user
interface,
using a fake browser, and mimic the actions a user would do.
ensure that your code is working correctly. They go through the user
interface,
using a fake browser, and mimic the actions a user would do.
Why
---
If you are not familiar with software tests, you may be wondering why you
would
need this. Every time you make a change to your application, you have to test
it. This means going through all the pages and making sure they are still
If you are not familiar with software tests, you may be wondering why you
would need this. Every time you make a change to your application, you have to
test
it. This means going through all the pages and making sure they are still
working. Functional tests save you a lot of time, because they enable you to
test your application in usually under a second by running a single command.
For more information on functional testing, unit testing, and automated
software tests in general, check out `PHPUnit <https://github.com/sebastianbergmann/phpunit>`_
and `Bulat Shakirzyanov's talk on Clean Code <http://www.slideshare.net/avalanche123/clean-code-5609451>`_.
software tests in general, check out `PHPUnit
<https://github.com/sebastianbergmann/phpunit>`_ and `Bulat Shakirzyanov's
talk on Clean Code
<http://www.slideshare.net/avalanche123/clean-code-5609451>`_.
PHPUnit
-------
`PHPUnit <https://github.com/sebastianbergmann/phpunit>`_
is the de-facto standard testing framework for PHP. It was built for
writing unit tests, but it can be used for functional tests too. You write
tests by creating a new class, that extends the ``PHPUnit_Framework_TestCase``.
Your test cases are
methods prefixed with ``test``::
`PHPUnit <https://github.com/sebastianbergmann/phpunit>`_
is the de-facto
standard testing framework for PHP. It was built for writing unit tests, but
it can be used for functional tests too. You write tests by creating a new
class, that extends the ``PHPUnit_Framework_TestCase``. Your test cases are
methods prefixed with ``test``::
class ContactFormTest extends PHPUnit_Framework_TestCase
{
...
...
@@ -120,8 +122,9 @@ executed before every test.
// ...
}
The WebTestCase provides a ``createClient`` method. A client acts as a browser,
and allows you to interact with your application. Here's how it works::
The WebTestCase provides a ``createClient`` method. A client acts as a
browser, and allows you to interact with your application. Here's how it
works::
public function testInitialPage()
{
...
...
@@ -148,8 +151,8 @@ application.
.. note::
You can find some documentation for it in `the client section of the
testing
chapter of the Symfony2 documentation
You can find some documentation for it in `the client section of the
testing
chapter of the Symfony2 documentation
<http://symfony.com/doc/current/book/testing.html#the-test-client>`_.
Crawler
...
...
@@ -168,8 +171,9 @@ Configuration
-------------
The suggested way to configure PHPUnit is to create a ``phpunit.xml.dist``
file, a ``tests`` folder and your tests in ``tests/YourApp/Tests/YourTest.php``.
The ``phpunit.xml.dist`` file should look like this:
file, a ``tests`` folder and your tests in
``tests/YourApp/Tests/YourTest.php``. The ``phpunit.xml.dist`` file should
look like this:
.. code-block:: xml
...
...
doc/usage.rst
View file @
7a376eb3
...
...
@@ -83,14 +83,13 @@ 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.
* *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.
``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 is defined using a closure like this::
...
...
@@ -98,22 +97,22 @@ The controller is defined using a closure like this::
// 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.
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 th
e
``Closure`` class, we
will not make a distinction here.
Closures that do not import scope are referred to as lambdas.
Because in
PHP all anonymous functions are instances of the ``Closure`` class, w
e
will not make a distinction here.
The return value of the closure becomes the content of the page.
There is also an alternate way for defining controllers using a
class method. The syntax for that is ``ClassName::methodName``.
Static methods are also
possible.
There is also an alternate way for defining controllers using a
class method.
The syntax for that is ``ClassName::methodName``. Static methods are also
possible.
Example GET route
~~~~~~~~~~~~~~~~~
...
...
@@ -140,15 +139,14 @@ Here is an example definition of a ``GET`` route::
});
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.
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::
Now, you can create another controller for viewing individual blog posts::
$app->get('/blog/show/{id}', function (Silex\Application $app, $id) use ($blogPosts) {
if (!isset($blogPosts[$id])) {
...
...
@@ -161,8 +159,8 @@ posts::
"<p>{$post['body']}</p>";
});
This route definition has a variable ``{id}`` part which is passed
to the
closure.
This route definition has a variable ``{id}`` part which is passed
to the
closure.
When the post does not exist, we are using ``abort()`` to stop the request
early. It actually throws an exception, which we will see how to handle later
...
...
@@ -188,19 +186,18 @@ It is pretty straightforward.
.. note::
There is a :doc:`SwiftmailerServiceProvider <providers/swiftmailer>`
included
that you can use instead of ``mail()``.
There is a :doc:`SwiftmailerServiceProvider <providers/swiftmailer>`
included
that you can use instead of ``mail()``.
The current ``request`` is automatically injected by Silex to the Closure
thanks to the type hinting. It is an instance of `Request
<http://api.symfony.com/master/Symfony/Component/HttpFoundation/Request.html>`_,
so you can fetch variables using the request ``get`` method.
Instead of returning a string we are returning an instance of
`Response
Instead of returning a string we are returning an instance of `Response
<http://api.symfony.com/master/Symfony/Component/HttpFoundation/Response.html>`_.
This allows setting an HTTP
status code, in this case it is set to ``201
Created``.
This allows setting an HTTP
status code, in this case it is set to ``201
Created``.
.. note::
...
...
@@ -211,8 +208,8 @@ 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::
methods on your application: ``get``, ``post``, ``put``, ``delete``. You
can
also call ``match``, which will match all methods::
$app->match('/blog', function () {
...
...
...
@@ -241,7 +238,8 @@ You can match multiple methods with one controller using regex syntax::
Route variables
~~~~~~~~~~~~~~~
As it has been shown before you can define variable parts in a route like this::
As it has been shown before you can define variable parts in a route like
this::
$app->get('/blog/show/{id}', function ($id) {
...
...
...
@@ -254,7 +252,8 @@ closure arguments match the names of the variable parts::
...
});
While it's not suggested, you could also do this (note the switched arguments)::
While it's not suggested, you could also do this (note the switched
arguments)::
$app->get('/blog/show/{postId}/{commentId}', function ($commentId, $postId) {
...
...
...
@@ -350,10 +349,10 @@ have the value ``index``.
Named routes
~~~~~~~~~~~~
Some providers (such as ``UrlGeneratorProvider``) 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::
Some providers (such as ``UrlGeneratorProvider``) 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 () {
...
...
...
@@ -368,15 +367,15 @@ object that is returned by the routing methods::
.. note::
It only makes sense to name routes if you use providers that make use
of
the ``RouteCollection``.
It only makes sense to name routes if you use providers that make use
of
the ``RouteCollection``.
Before, after and finish filters
--------------------------------
Silex allows you to run code before, after every request and even after the
response has been sent. This happens through ``before``, ``after`` and
``finish``
filters. All you need to do is pass a closure::
response has been sent. This happens through ``before``, ``after`` and
``finish``
filters. All you need to do is pass a closure::
$app->before(function () {
// set up
...
...
@@ -390,8 +389,8 @@ filters. All you need to do is pass a closure::
// after response has been sent
});
The before filter has access to the current Request, and can short-circuit
the
whole rendering by returning a Response::
The before filter has access to the current Request, and can short-circuit
the
whole rendering by returning a Response::
$app->before(function (Request $request) {
// redirect the user to the login screen if access to the Resource is protected
...
...
@@ -491,12 +490,12 @@ the defaults for new controllers.
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.
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::
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;
...
...
@@ -535,9 +534,9 @@ once a response is returned, the following handlers are ignored.
.. note::
Silex ships with a provider for `Monolog
<https://github.com/Seldaek/monolog>`_
which handles logging of errors. Check out the *Providers* chapter
for details.
Silex ships with a provider for `Monolog
<https://github.com/Seldaek/monolog>`_ which handles logging of errors.
Check out the *Providers* chapter
for details.
.. tip::
...
...
@@ -571,8 +570,8 @@ early::
Redirects
---------
You can redirect to another page by returning a redirect response, which
you
can create by calling the ``redirect`` method::
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');
...
...
@@ -672,10 +671,8 @@ JSON
----
If you want to return JSON data, you can use the ``json`` helper method.
Simply pass it your data, status code and headers, and it will create a
JSON response for you.
.. code-block:: php
Simply pass it your data, status code and headers, and it will create a JSON
response for you::
$app->get('/users/{id}', function ($id) use ($app) {
$user = getUser($id);
...
...
@@ -691,10 +688,8 @@ JSON response for you.
Streaming
---------
It's possible to create a streaming response, which is important in cases
when you cannot buffer the data being sent.
.. code-block:: php
It's possible to create a streaming response, which is important in cases when
you cannot buffer the data being sent::
$app->get('/images/{file}', function ($file) use ($app) {
if (!file_exists(__DIR__.'/images/'.$file)) {
...
...
@@ -708,10 +703,8 @@ when you cannot buffer the data being sent.
return $app->stream($stream, 200, array('Content-Type' => 'image/png'));
});
If you need to send chunks, make sure you call ``ob_flush`` and ``flush`` after
every chunk.
.. code-block:: php
If you need to send chunks, make sure you call ``ob_flush`` and ``flush``
after every chunk::
$stream = function () {
$fh = fopen('http://www.example.com/', 'rb');
...
...
@@ -732,8 +725,8 @@ Escaping
~~~~~~~~
When outputting any user input (either route variables GET/POST variables
obtained from the request), you will have to make sure to escape it
correctly,
to prevent Cross-Site-Scripting attacks.
obtained from the request), you will have to make sure to escape it
correctly,
to prevent Cross-Site-Scripting attacks.
* **Escaping HTML**: PHP provides the ``htmlspecialchars`` function for this.
Silex provides a shortcut ``escape`` method::
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment