diff --git a/book/controller.rst b/book/controller.rst index cc484c0cd3f..609ce6cd859 100644 --- a/book/controller.rst +++ b/book/controller.rst @@ -429,35 +429,47 @@ A great way to see the core functionality in action is to look in the Redirecting ~~~~~~~~~~~ -If you want to redirect the user to another page, use the -:method:`Symfony\\Bundle\\FrameworkBundle\\Controller\\Controller::redirect` -method:: +If you want to redirect the user to another page, use the ``redirectToRoute()`` method:: public function indexAction() { - return $this->redirect($this->generateUrl('homepage')); + return $this->redirectToRoute('homepage'); + + // redirectToRoute is equivalent to using redirect() and generateUrl() together: + // return $this->redirect($this->generateUrl('homepage'), 301); } -The ``generateUrl()`` method is just a helper function that generates the URL -for a given route. For more information, see the :doc:`Routing ` -chapter. +.. versionadded:: 2.6 + The ``redirectToRoute()`` method was added in Symfony 2.6. Previously (and still now), you + could use ``redirect()`` and ``generateUrl()`` together for this (see the example above). + +Or, if you want to redirect externally, just use ``redirect()`` and pass it the URL:: + + public function indexAction() + { + return $this->redirect('http://symfony.com/doc'); + } -By default, the ``redirect()`` method performs a 302 (temporary) redirect. To +By default, the ``redirectToRoute()`` method performs a 302 (temporary) redirect. To perform a 301 (permanent) redirect, modify the second argument:: public function indexAction() { - return $this->redirect($this->generateUrl('homepage'), 301); + return $this->redirectToRoute('homepage', array(), 301); } .. tip:: - The ``redirect()`` method is simply a shortcut that creates a ``Response`` - object that specializes in redirecting the user. It's equivalent to:: + The ``redirectToRoute()`` method is simply a shortcut that creates a + ``Response`` object that specializes in redirecting the user. It's + equivalent to:: use Symfony\Component\HttpFoundation\RedirectResponse; - return new RedirectResponse($this->generateUrl('homepage')); + public function indexAction() + { + return new RedirectResponse($this->generateUrl('homepage')); + } .. index:: single: Controller; Rendering templates @@ -623,12 +635,14 @@ For example, imagine you're processing a form submit:: if ($form->isValid()) { // do some sort of processing - $request->getSession()->getFlashBag()->add( + $this->addFlash( 'notice', 'Your changes were saved!' ); - return $this->redirect($this->generateUrl(...)); + // $this->addFlash is equivalent to $this->get('session')->getFlashBag()->add + + return $this->redirectToRoute(...); } return $this->render(...); @@ -638,8 +652,8 @@ After processing the request, the controller sets a ``notice`` flash message in the session and then redirects. The name (``notice``) isn't significant - it's just something you invent and reference next. -In the template of the next page (or even better, in your base layout template), -the following code will render the ``notice`` message: +In the template of the next action, the following code could be used to render +the ``notice`` message: .. configuration-block:: diff --git a/book/doctrine.rst b/book/doctrine.rst index e60ab0118fe..7c69e801cca 100644 --- a/book/doctrine.rst +++ b/book/doctrine.rst @@ -667,7 +667,7 @@ you have a route that maps a product id to an update action in a controller:: $product->setName('New product name!'); $em->flush(); - return $this->redirect($this->generateUrl('homepage')); + return $this->redirectToRoute('homepage'); } Updating an object involves just three steps: @@ -778,6 +778,8 @@ entities (the topic of :ref:`relations ` will be covered later), group, etc. For more information, see the official `Doctrine Query Language`_ documentation. +.. _book-doctrine-custom-repository-classes: + Custom Repository Classes ~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/book/forms.rst b/book/forms.rst index 0ee84be5b5e..5441564b13a 100644 --- a/book/forms.rst +++ b/book/forms.rst @@ -234,7 +234,7 @@ controller:: if ($form->isValid()) { // perform some action, such as saving the task to the database - return $this->redirect($this->generateUrl('task_success')); + return $this->redirectToRoute('task_success'); } // ... @@ -319,7 +319,7 @@ querying if the "Save and add" button was clicked:: ? 'task_new' : 'task_success'; - return $this->redirect($this->generateUrl($nextAction)); + return $this->redirectToRoute($nextAction); } .. index:: @@ -1237,7 +1237,7 @@ it after a form submission can be done when the form is valid:: $em->persist($task); $em->flush(); - return $this->redirect($this->generateUrl('task_success')); + return $this->redirectToRoute('task_success'); } If, for some reason, you don't have access to your original ``$task`` object, diff --git a/book/http_cache.rst b/book/http_cache.rst index 1c1e5f64fa8..46ac1dd1208 100644 --- a/book/http_cache.rst +++ b/book/http_cache.rst @@ -166,6 +166,12 @@ kernel:: The caching kernel will immediately act as a reverse proxy - caching responses from your application and returning them to the client. +.. caution:: + + If you're using the :ref:`framework.http_method_override ` + option to read the HTTP method from a ``_method`` parameter, see the + above link for a tweak you need to make. + .. tip:: The cache kernel has a special ``getLog()`` method that returns a string diff --git a/book/installation.rst b/book/installation.rst index 52b79df7f90..d5ed197e377 100644 --- a/book/installation.rst +++ b/book/installation.rst @@ -98,6 +98,17 @@ number as the second argument of the ``new`` command: # Windows c:\projects\> php symfony.phar new my_project_name 2.3.23 +If you want your project to be based on the latest :ref:`Symfony LTS version `, +pass ``lts`` as the second argument of the ``new`` command: + +.. code-block:: bash + + # Linux, Mac OS X + $ symfony new my_project_name lts + + # Windows + c:\projects\> php symfony.phar new my_project_name lts + Read the :doc:`Symfony Release process ` to better understand why there are several Symfony versions and which one to use for your projects. diff --git a/book/performance.rst b/book/performance.rst index e3f296484ad..e3496b42476 100644 --- a/book/performance.rst +++ b/book/performance.rst @@ -18,8 +18,9 @@ Use a Byte Code Cache (e.g. APC) One of the best (and easiest) things that you should do to improve your performance is to use a "byte code cache". The idea of a byte code cache is to remove the need to constantly recompile the PHP source code. There are a number of -`byte code caches`_ available, some of which are open source. The most widely -used byte code cache is probably `APC`_ +`byte code caches`_ available, some of which are open source. As of PHP 5.5, +PHP comes with `OPcache`_ built-in. For older versions, the most widely used +byte code cache is probably `APC`_ Using a byte code cache really has no downside, and Symfony has been architected to perform really well in this type of environment. @@ -139,6 +140,7 @@ feature is disabled in the byte code cache (e.g. ``apc.stat=0`` in APC), there is no longer a reason to use a bootstrap file. .. _`byte code caches`: http://en.wikipedia.org/wiki/List_of_PHP_accelerators +.. _`OPcache`: http://php.net/manual/en/book.opcache.php .. _`APC`: http://php.net/manual/en/book.apc.php .. _`autoload.php`: https://github.com/symfony/symfony-standard/blob/master/app/autoload.php .. _`bootstrap file`: https://github.com/sensio/SensioDistributionBundle/blob/master/Composer/ScriptHandler.php diff --git a/book/propel.rst b/book/propel.rst index d1b812f4653..7cf5755c09b 100644 --- a/book/propel.rst +++ b/book/propel.rst @@ -244,7 +244,7 @@ have a route that maps a product id to an update action in a controller:: $product->setName('New product name!'); $product->save(); - return $this->redirect($this->generateUrl('homepage')); + return $this->redirectToRoute('homepage'); } } diff --git a/book/routing.rst b/book/routing.rst index e7cd6c8e5ba..2b253a2d563 100644 --- a/book/routing.rst +++ b/book/routing.rst @@ -45,7 +45,7 @@ The route is simple: class BlogController extends Controller { /** - * @Route("/blog/{slug}") + * @Route("/blog/{slug}", name="blog_show") */ public function showAction($slug) { diff --git a/book/security.rst b/book/security.rst index c3b01c3f530..300569c53c9 100644 --- a/book/security.rst +++ b/book/security.rst @@ -813,20 +813,29 @@ You can easily deny access from inside a controller:: public function helloAction($name) { - if (false === $this->get('security.authorization_checker')->isGranted('ROLE_ADMIN')) { - throw $this->createAccessDeniedException(); - } + // The second parameter is used to specify on what object the role is tested. + $this->denyAccessUnlessGranted('ROLE_ADMIN', null, 'Unable to access this page!'); + + // Old way : + // if (false === $this->get('security.authorization_checker')->isGranted('ROLE_ADMIN')) { + // throw $this->createAccessDeniedException('Unable to access this page!'); + // } // ... } .. versionadded:: 2.6 - The ``security.authorization_checker`` service was introduced in Symfony 2.6. Prior - to Symfony 2.6, you had to use the ``isGranted()`` method of the ``security.context`` service. + The ``denyAccessUnlessGranted()`` method was introduced in Symfony 2.6. Previously (and + still now), you could check access directly and throw the ``AccessDeniedException`` as shown + in the example above). + +.. versionadded:: 2.6 + The ``security.authorization_checker`` service was introduced in Symfony 2.6. Prior + to Symfony 2.6, you had to use the ``isGranted()`` method of the ``security.context`` service. -The :method:`Symfony\\Bundle\\FrameworkBundle\\Controller\\Controller::createAccessDeniedException` -method creates a special :class:`Symfony\\Component\\Security\\Core\\Exception\\AccessDeniedException` -object, which ultimately triggers a 403 HTTP response inside Symfony. +In both cases, a special +:class:`Symfony\\Component\\Security\\Core\\Exception\\AccessDeniedException` +is thrown, which ultimately triggers a 403 HTTP response inside Symfony. That's it! If the user isn't logged in yet, they will be asked to login (e.g. redirected to the login page). If they *are* logged in, they'll be shown diff --git a/book/testing.rst b/book/testing.rst index 2faa734a68e..50e22186c6c 100644 --- a/book/testing.rst +++ b/book/testing.rst @@ -394,7 +394,7 @@ or perform more complex requests. Some useful examples:: array('photo' => $photo) ); - // Perform a DELETE requests and pass HTTP headers + // Perform a DELETE request and pass HTTP headers $client->request( 'DELETE', '/post/12', diff --git a/book/validation.rst b/book/validation.rst index 1abbaacfc5d..b6bbd2e7901 100644 --- a/book/validation.rst +++ b/book/validation.rst @@ -232,7 +232,7 @@ workflow looks like the following from inside a controller:: if ($form->isValid()) { // the validation passed, do something with the $author object - return $this->redirect($this->generateUrl(...)); + return $this->redirectToRoute(...); } return $this->render('author/form.html.twig', array( diff --git a/components/asset/index.rst b/components/asset/index.rst new file mode 100644 index 00000000000..14d04b7eb6f --- /dev/null +++ b/components/asset/index.rst @@ -0,0 +1,7 @@ +Asset +===== + +.. toctree:: + :maxdepth: 2 + + introduction diff --git a/components/asset/introduction.rst b/components/asset/introduction.rst new file mode 100644 index 00000000000..eb2d1d22ba2 --- /dev/null +++ b/components/asset/introduction.rst @@ -0,0 +1,289 @@ +.. index:: + single: Asset + single: Components; Asset + +The Asset Component +=================== + + The Asset component manages URL generation and versioning of web assets such + as CSS stylesheets, JavaScript files and image files. + +In the past, it was common for web applications to hardcode URLs of web assets. +For example: + +.. code-block:: html + + + + + + + +This practice is no longer recommended unless the web application is extremely +simple. Hardcoding URLs can be a disadvantage because: + +* **Templates get verbose**: you have to write the full path for each + asset. When using the Asset component, you can group assets in packages to + avoid repeating the common part of their path; +* **Versioning is difficult**: it has to be custom managed for each + application. Adding a version to the asset URLs is essential for some applications + because it allows to control how the assets are cached. The Asset component + allows to define different versioning strategies for each package; +* **Moving assets location** is cumbersome and error-prone: it requires you to + carefully update the URLs of all assets included in all templates. The Asset + component allows to move assets effortlessly just by changing the base path + value associated with the package of assets; +* **It's nearly impossible to use multiple CDNs**: this technique requires to + change the URL of the asset randomly for each request. The Asset component + provides out-of-the-box support for any number of multiple CDNs, both regular + (``http://``) and secure (``https://``). + +Installation +------------ + +You can install the component in two different ways: + +* :doc:`Install it via Composer ` (``symfony/asset`` on `Packagist`_); +* Use the official Git repository (https://github.com/symfony/Asset). + +Usage +----- + +Asset Packages +~~~~~~~~~~~~~~ + +The Asset component manages assets through packages. A package groups all the +assets which share the same properties: versioning strategy, base path, CDN hosts, +etc. In the following basic example, a package is created to manage assets without +any versioning:: + + use Symfony\Component\Asset\Package; + use Symfony\Component\Asset\VersionStrategy\EmptyVersionStrategy; + + $package = new Package(new EmptyVersionStrategy()); + + echo $package->getUrl('/image.png'); + // result: /image.png + +Packages implement the :class:`Symfony\\Component\\Asset\\PackageInterface`, +which defines the following two methods: + +:method:`Symfony\\Component\\Asset\\PackageInterface::getVersion` + Returns the asset version for an asset. + +:method:`Symfony\\Component\\Asset\\PackageInterface::getUrl` + Returns an absolute or root-relative public path. + +Versioned Assets +~~~~~~~~~~~~~~~~ + +One of the main features of the Asset component is to manage the versioning of +the application's assets. Asset versions are commonly used to control how these +assets are cached. + +Instead of relying on a simple version mechanism, the Asset component allows to +define advanced versioning strategies via PHP classes. The two built-in strategies +provided by the component are :class:`Symfony\\Component\\Asset\\VersionStrategy\\EmptyVersionStrategy`, +which doesn't add any version to the asset and :class:`Symfony\\Component\\Asset\\VersionStrategy\\StaticVersionStrategy`, +which allows to set the version with a format string. + +In this example, the ``StaticVersionStrategy`` is used to append the ``v1`` +suffix to any asset path:: + + use Symfony\Component\Asset\Package; + use Symfony\Component\Asset\VersionStrategy\StaticVersionStrategy; + + $package = new Package(new StaticVersionStrategy('v1')); + + echo $package->getUrl('/image.png'); + // result: /image.png?v1 + +In case you want to modify the version format, pass a sprintf-compatible format +string as the second argument of the ``StaticVersionStrategy`` constructor:: + + // put the 'version' word before the version value + $package = new Package(new StaticVersionStrategy('v1', '%s?version=%s')); + + echo $package->getUrl('/image.png'); + // result: /image.png?version=v1 + + // put the asset version before its path + $package = new Package(new StaticVersionStrategy('v1', '%2$s/%1$s')); + + echo $package->getUrl('/image.png'); + // result: /v1/image.png + +Custom Version Strategies +......................... + +Use the :class:`Symfony\\Component\\Asset\\VersionStrategy\\VersionStrategyInterface` +to define your own versioning strategy. For example, your application may need +to append the current date to all its web assets in order to bust the cache +every day:: + + use Symfony\Component\Asset\VersionStrategy\VersionStrategyInterface; + + class DateVersionStrategy implements VersionStrategyInterface + { + private $version; + + public function __construct() + { + $this->version = date('Ymd'); + } + + public function getVersion($path) + { + return $this->version; + } + + public function applyVersion($path) + { + return sprintf('%s?v=%s', $path, $this->getVersion($path)); + } + } + +Grouped Assets +~~~~~~~~~~~~~~ + +It's common for applications to store their assets in a common path. If that's +your case, replace the default :class:`Symfony\\Component\\Asset\\Package` class +by :class:`Symfony\\Component\\Asset\\PathPackage` to avoid repeating the same +path time and again:: + + use Symfony\Component\Asset\PathPackage; + // ... + + $package = new PathPackage('/static/images', new StaticVersionStrategy('v1')); + + echo $package->getUrl('/logo.png'); + // result: /static/images/logo.png?v1 + +Request Context Aware Assets +............................ + +If you are also using the HttpFoundation component in your project, for example +in a Symfony application, the ``PathPackage`` class can take into account the +context of the current request:: + + use Symfony\Component\Asset\PathPackage; + use Symfony\Component\Asset\Context\RequestStackContext; + // ... + + $package = new PathPackage( + '/static/images', + new StaticVersionStrategy('v1'), + new RequestStackContext($requestStack) + ); + + echo $package->getUrl('/logo.png'); + // result: /somewhere/static/images/logo.png?v1 + +When the request context is set (via an optional third argument), in addition to +the configured base path, ``PathPackage`` also prepends the current request base +URL (``/somewhere/`` in this example) to assets. This allows your website to be +hosted anywhere under the web server root directory. + +Absolute Assets and CDNs +~~~~~~~~~~~~~~~~~~~~~~~~ + +Applications that host their assets on different domains and CDNs (*Content +Delivery Networks*) should use the :class:`Symfony\\Component\\Asset\\UrlPackage` +class to generate absolute URLs for their assets:: + + use Symfony\Component\Asset\UrlPackage; + // ... + + $package = new UrlPackage( + 'http://static.example.com/images/', + new StaticVersionStrategy('v1') + ); + + echo $package->getUrl('/logo.png'); + // result: http://static.example.com/images/logo.png?v1 + +In case you serve assets from more than one domain to improve application +performance, pass an array of URLs as the first argument of ``UrlPackage`` +constructor:: + + use Symfony\Component\Asset\UrlPackage; + // ... + + $urls = array( + 'http://static1.example.com/images/', + 'http://static2.example.com/images/', + ); + $package = new UrlPackage($urls, new StaticVersionStrategy('v1')); + + echo $package->getUrl('/logo.png'); + // result: http://static1.example.com/images/logo.png?v1 + +The selection of the domain which will serve the asset is deterministic, meaning +that each asset will be always served by the same domain. This behavior simplifies +the management of HTTP cache. + +Request Context Aware Assets +............................ + +Similarly to application-relative assets, absolute assets can also take into +account the context of the current request. In this case, only the request +scheme is considered, in order to select the appropriate base URL (HTTPs or +protocol-relative URLs for HTTPs requests, any base URL for HTTP requests):: + + use Symfony\Component\Asset\UrlPackage; + use Symfony\Component\Asset\Context\RequestStackContext; + // ... + + $package = new UrlPackage( + array('http://example.com/', 'https://example.com/'), + new StaticVersionStrategy('v1'), + new RequestStackContext($requestStack) + ); + + echo $package->getUrl('/logo.png'); + // result: https://example.com/logo.png?v1 + +Named Packages +~~~~~~~~~~~~~~ + +Applications that manage lots of different assets may need to group them in +packages with the same versioning strategy and base path. The Asset component +includes a :class:`Symfony\\Component\\Asset\\Packages` class to simplify +management of several packages. + +In the following example, all packages use the same versioning strategy, but +they all have different base paths:: + + use Symfony\Component\Asset\Package; + use Symfony\Component\Asset\PathPackage; + use Symfony\Component\Asset\UrlPackage; + use Symfony\Component\Asset\Packages; + // ... + + $versionStrategy = new StaticVersionStrategy('v1'); + + $defaultPackage = new Package($versionStrategy); + + $namedPackages = array( + 'img' => new UrlPackage('http://img.example.com/', $versionStrategy), + 'doc' => new PathPackage('/somewhere/deep/for/documents', $versionStrategy), + ); + + $packages = new Packages($defaultPackage, $namedPackages) + +The ``Packages`` class allows to define a default package, which will be applied +to assets that don't define the name of package to use. In addition, this +application defines a package named ``img`` to serve images from an external +domain and a ``doc`` package to avoid repeating long paths when linking to a +document inside a template:: + + echo $packages->getUrl('/main.css'); + // result: /main.css?v1 + + echo $packages->getUrl('/logo.png', 'img'); + // result: http://img.example.com/logo.png?v1 + + echo $packages->getUrl('/resume.pdf', 'doc'); + // result: /somewhere/deep/for/documents/resume.pdf?v1 + +.. _Packagist: https://packagist.org/packages/symfony/asset diff --git a/components/config/definition.rst b/components/config/definition.rst index af4a72338ee..27beb52e4d6 100644 --- a/components/config/definition.rst +++ b/components/config/definition.rst @@ -95,13 +95,13 @@ Node Type ~~~~~~~~~ It is possible to validate the type of a provided value by using the appropriate -node definition. Node type are available for: +node definition. Node types are available for: -* scalar +* scalar (generic type that includes booleans, strings, integers, floats and ``null``) * boolean * integer * float -* enum +* enum (similar to scalar, but it only allows a finite set of values) * array * variable (no validation) @@ -288,7 +288,8 @@ All options can be documented using the :method:`Symfony\\Component\\Config\\Definition\\Builder\\NodeDefinition::info` method. -The info will be printed as a comment when dumping the configuration tree. +The info will be printed as a comment when dumping the configuration tree with +the ``config:dump`` command. .. versionadded:: 2.6 Since Symfony 2.6, the info will also be added to the exception message diff --git a/components/config/introduction.rst b/components/config/introduction.rst index 11dae2e1d78..b4d075c3b58 100644 --- a/components/config/introduction.rst +++ b/components/config/introduction.rst @@ -9,13 +9,6 @@ The Config Component combine, autofill and validate configuration values of any kind, whatever their source may be (YAML, XML, INI files, or for instance a database). -.. caution:: - - The ``IniFileLoader`` parses the file contents using the - :phpfunction:`parse_ini_file` function, therefore, you can only set - parameters to string values. To set parameters to other data types - (e.g. boolean, integer, etc), the other loaders are recommended. - Installation ------------ diff --git a/components/config/resources.rst b/components/config/resources.rst index a1d46565803..1a5fba23c2b 100644 --- a/components/config/resources.rst +++ b/components/config/resources.rst @@ -4,6 +4,13 @@ Loading Resources ================= +.. caution:: + + The ``IniFileLoader`` parses the file contents using the + :phpfunction:`parse_ini_file` function. Therefore, you can only set + parameters to string values. To set parameters to other data types + (e.g. boolean, integer, etc), the other loaders are recommended. + Locating Resources ------------------ diff --git a/components/console/introduction.rst b/components/console/introduction.rst index 18861b5831d..13fb3578fc8 100644 --- a/components/console/introduction.rst +++ b/components/console/introduction.rst @@ -20,15 +20,6 @@ You can install the component in 2 different ways: * :doc:`Install it via Composer ` (``symfony/console`` on `Packagist`_); * Use the official Git repository (https://github.com/symfony/Console). -.. note:: - - Windows does not support ANSI colors by default so the Console component detects and - disables colors where Windows does not have support. However, if Windows is not - configured with an ANSI driver and your console commands invoke other scripts which - emit ANSI color sequences, they will be shown as raw escape characters. - - To enable ANSI color support for Windows, please install `ANSICON`_. - Creating a basic Command ------------------------ @@ -124,6 +115,14 @@ This prints:: Coloring the Output ~~~~~~~~~~~~~~~~~~~ +.. note:: + + By default, the Windows command console doesn't support output coloring. The + Console component disables output coloring for Windows systems, but if your + commands invoke other scripts which emit color sequences, they will be + wrongly displayed as raw escape characters. Install the `ConEmu`_ or `ANSICON`_ + free applications to add coloring support to your Windows command console. + Whenever you output text, you can surround the text with tags to color its output. For example:: @@ -324,9 +323,11 @@ declare a one-letter shortcut that you can call with a single dash like .. tip:: - It is also possible to make an option *optionally* accept a value (so that - ``--yell``, ``--yell=loud`` or ``--yell loud`` work). Options can also be configured to - accept an array of values. + There is nothing forbidding you to create a command with an option that + optionally accepts a value. However, there is no way you can distinguish + when the option was used without a value (``command --yell``) or when it + wasn't used at all (``command``). In both cases, the value retrieved for + the option will be ``null``. For example, add a new option to the command that can be used to specify how many times in a row the message should be printed:: @@ -533,4 +534,5 @@ Learn More! * :doc:`/components/console/console_arguments` .. _Packagist: https://packagist.org/packages/symfony/console +.. _ConEmu: https://code.google.com/p/conemu-maximus5/ .. _ANSICON: https://github.com/adoxa/ansicon/releases diff --git a/components/dependency_injection/factories.rst b/components/dependency_injection/factories.rst index 56acbe9a7f1..edc34b7b3a4 100644 --- a/components/dependency_injection/factories.rst +++ b/components/dependency_injection/factories.rst @@ -69,6 +69,14 @@ configure the service container to use the $container->setDefinition('newsletter_manager', $definition); +.. note:: + + When using a factory to create services, the value chosen for the ``class`` + option has no effect on the resulting service. The actual class name only + depends on the object that is returned by the factory. However, the configured + class name may be used by compiler passes and therefore should be set to a + sensible value. + Now, the method will be called statically. If the factory class itself should be instantiated and the resulting object's method called, configure the factory itself as a service. In this case, the method (e.g. get) should be changed to diff --git a/components/event_dispatcher/introduction.rst b/components/event_dispatcher/introduction.rst index 573061b0556..e3f8da1916f 100644 --- a/components/event_dispatcher/introduction.rst +++ b/components/event_dispatcher/introduction.rst @@ -212,14 +212,14 @@ instance of ``Symfony\Component\HttpKernel\Event\FilterResponseEvent``:: and the :doc:`DependencyInjection component `, you can use the - :class:`Symfony\\Component\\HttpKernel\\DependencyInjection\\RegisterListenersPass` - from the HttpKernel component to tag services as event listeners:: + :class:`Symfony\\Component\\EventDispatcher\\DependencyInjection\\RegisterListenersPass` + to tag services as event listeners:: use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Definition; use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag; use Symfony\Component\DependencyInjection\Reference; - use Symfony\Component\HttpKernel\DependencyInjection\RegisterListenersPass; + use Symfony\Component\EventDispatcher\DependencyInjection\RegisterListenersPass; $containerBuilder = new ContainerBuilder(new ParameterBag()); $containerBuilder->addCompilerPass(new RegisterListenersPass()); diff --git a/components/form/introduction.rst b/components/form/introduction.rst index c53e7cd2451..825b2402c17 100644 --- a/components/form/introduction.rst +++ b/components/form/introduction.rst @@ -587,7 +587,7 @@ method: // ... perform some action, such as saving the data to the database - return $this->redirect($this->generateUrl('task_success')); + return $this->redirectToRoute('task_success'); } // ... diff --git a/components/index.rst b/components/index.rst index d16b78de06f..41f72d049a4 100644 --- a/components/index.rst +++ b/components/index.rst @@ -5,6 +5,7 @@ The Components :hidden: using_components + asset/index class_loader/index config/index console/index diff --git a/components/intl.rst b/components/intl.rst index 6e85544c774..c638f8bd2f6 100644 --- a/components/intl.rst +++ b/components/intl.rst @@ -60,80 +60,6 @@ code:: $loader->registerPrefixFallback('/path/to/Icu/Resources/stubs'); } -.. sidebar:: ICU and Deployment Problems - - The intl extension internally uses the `ICU library`_ to obtain localization - data such as number formats in different languages, country names and more. - To make this data accessible to userland PHP libraries, Symfony ships a copy - in the `Icu component`_. - - Depending on the ICU version compiled with your intl extension, a matching - version of that component needs to be installed. It sounds complicated, - but usually Composer does this for you automatically: - - * 1.0.*: when the intl extension is not available - * 1.1.*: when intl is compiled with ICU 3.8 or higher - * 1.2.*: when intl is compiled with ICU 4.4 or higher - - These versions are important when you deploy your application to a **server with - a lower ICU version** than your development machines, because deployment will - fail if: - - * the development machines are compiled with ICU 4.4 or higher, but the - server is compiled with a lower ICU version than 4.4; - * the intl extension is available on the development machines but not on - the server. - - For example, consider that your development machines ship ICU 4.8 and the server - ICU 4.2. When you run ``composer update`` on the development machine, version - 1.2.* of the Icu component will be installed. But after deploying the - application, ``composer install`` will fail with the following error: - - .. code-block:: bash - - $ composer install - Loading composer repositories with package information - Installing dependencies from lock file - Your requirements could not be resolved to an installable set of packages. - - Problem 1 - - symfony/icu 1.2.x requires lib-icu >=4.4 -> the requested linked - library icu has the wrong version installed or is missing from your - system, make sure to have the extension providing it. - - The error tells you that the requested version of the Icu component, version - 1.2, is not compatible with PHP's ICU version 4.2. - - One solution to this problem is to run ``composer update`` instead of - ``composer install``. It is highly recommended **not** to do this. The - ``update`` command will install the latest versions of each Composer dependency - to your production server and potentially break the application. - - A better solution is to fix your composer.json to the version required by the - production server. First, determine the ICU version on the server: - - .. code-block:: bash - - $ php -i | grep ICU - ICU version => 4.2.1 - - Then fix the Icu component in your ``composer.json`` file to a matching version: - - .. code-block:: json - - "require: { - "symfony/icu": "1.1.*" - } - - Set the version to - - * "1.0.*" if the server does not have the intl extension installed; - * "1.1.*" if the server is compiled with ICU 4.2 or lower. - - Finally, run ``composer update symfony/icu`` on your development machine, test - extensively and deploy again. The installation of the dependencies will now - succeed. - Writing and Reading Resource Bundles ------------------------------------ diff --git a/components/map.rst.inc b/components/map.rst.inc index 7b6ceae5db2..009284614ce 100644 --- a/components/map.rst.inc +++ b/components/map.rst.inc @@ -1,5 +1,9 @@ * :doc:`/components/using_components` +* :doc:`/components/asset/index` + + * :doc:`/components/asset/introduction` + * :doc:`/components/class_loader/index` * :doc:`/components/class_loader/introduction` diff --git a/components/serializer.rst b/components/serializer.rst index 729439acecf..78d057001a4 100644 --- a/components/serializer.rst +++ b/components/serializer.rst @@ -50,6 +50,12 @@ which Encoders and Normalizer are going to be available:: $serializer = new Serializer($normalizers, $encoders); +There are several normalizers available, e.g. the +:class:`Symfony\\Component\\Serializer\\Normalizer\\GetSetMethodNormalizer` or +the :class:`Symfony\\Component\\Serializer\\Normalizer\\PropertyNormalizer`. +To read more about them, refer to the `Normalizers`_ section of this page. All +the examples shown below use the ``GetSetMethodNormalizer``. + Serializing an Object --------------------- @@ -311,6 +317,28 @@ When serializing, you can set a callback to format a specific object property:: $serializer->serialize($person, 'json'); // Output: {"name":"cordoval", "age": 34, "createdAt": "2014-03-22T09:43:12-0500"} +Normalizers +----------- + +There are several types of normalizers available: + +:class:`Symfony\\Component\\Serializer\\Normalizer\\GetSetMethodNormalizer` + This normalizer reads the content of the class by calling the "getters" + (public methods starting with "get"). It will denormalize data by calling + the constructor and the "setters" (public methods starting with "set"). + + Objects are serialized to a map of property names (method name stripped of + the "get" prefix and converted to lower case) to property values. + +:class:`Symfony\\Component\\Serializer\\Normalizer\\PropertyNormalizer` + This normalizer directly reads and writes public properties as well as + **private and protected** properties. Objects are normalized to a map of + property names to property values. + +.. versionadded:: 2.6 The + :class:`Symfony\\Component\\Serializer\\Normalizer\\PropertyNormalizer` + class was introduced in Symfony 2.6. + Handling Circular References ---------------------------- diff --git a/contributing/code/core_team.rst b/contributing/code/core_team.rst index 6703647f609..3932df6b616 100644 --- a/contributing/code/core_team.rst +++ b/contributing/code/core_team.rst @@ -37,37 +37,37 @@ Active Core Members * **Project Leader**: - * **Fabien Potencier** (:leader:`fabpot`). + * **Fabien Potencier** (`fabpot`_). * **Mergers** (``@symfony/mergers`` on GitHub): - * **Bernhard Schussek** (:merger:`webmozart`) can merge into the Form_, + * **Bernhard Schussek** (`webmozart`_) can merge into the Form_, Validator_, Icu_, Intl_, Locale_, OptionsResolver_ and PropertyAccess_ components; - * **Tobias Schultze** (:merger:`Tobion`) can merge into the Routing_ - component; + * **Tobias Schultze** (`Tobion`_) can merge into the Routing_, + OptionsResolver_ and PropertyAccess_ components; - * **Romain Neutron** (:merger:`romainneutron`) can merge into the + * **Romain Neutron** (`romainneutron`_) can merge into the Process_ component; - * **Nicolas Grekas** (:merger:`nicolas-grekas`) can merge into the Debug_ + * **Nicolas Grekas** (`nicolas-grekas`_) can merge into the Debug_ component, the VarDumper_ component and the DebugBundle_; - * **Christophe Coevoet** (:merger:`stof`) can merge into the BrowserKit_, + * **Christophe Coevoet** (`stof`_) can merge into the BrowserKit_, Config_, Console_, DependencyInjection_, DomCrawler_, EventDispatcher_, HttpFoundation_, HttpKernel_, Serializer_, Stopwatch_, DoctrineBridge_, MonologBridge_, and TwigBridge_ components; - * **Kévin Dunglas** (:merger:`dunglas`) can merge into the Serializer_ + * **Kévin Dunglas** (`dunglas`_) can merge into the Serializer_ component. * **Deciders** (``@symfony/deciders`` on GitHub): - * **Jakub Zalas** (:decider:`jakzal`); - * **Jordi Boggiano** (:decider:`seldaek`); - * **Lukas Kahwe Smith** (:decider:`lsmith77`); - * **Ryan Weaver** (:decider:`weaverryan`). + * **Jakub Zalas** (`jakzal`_); + * **Jordi Boggiano** (`seldaek`_); + * **Lukas Kahwe Smith** (`lsmith77`_); + * **Ryan Weaver** (`weaverryan`_). Core Membership Application ~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -170,3 +170,14 @@ discretion of the **Project Leader**. .. _Validator: https://github.com/symfony/Validator .. _VarDumper: https://github.com/symfony/var-dumper .. _DebugBundle: https://github.com/symfony/debug-bundle +.. _`fabpot`: https://github.com/fabpot/ +.. _`webmozart`: https://github.com/webmozart/ +.. _`Tobion`: https://github.com/Tobion/ +.. _`romainneutron`: https://github.com/romainneutron/ +.. _`nicolas-grekas`: https://github.com/nicolas-grekas/ +.. _`stof`: https://github.com/stof/ +.. _`dunglas`: https://github.com/dunglas/ +.. _`jakzal`: https://github.com/jakzal/ +.. _`Seldaek`: https://github.com/Seldaek/ +.. _`lsmith77`: https://github.com/lsmith77/ +.. _`weaverryan`: https://github.com/weaverryan/ diff --git a/contributing/community/releases.rst b/contributing/community/releases.rst index 0f2dc92121f..988e39dc38f 100644 --- a/contributing/community/releases.rst +++ b/contributing/community/releases.rst @@ -60,6 +60,8 @@ Standard Versions A standard minor version is maintained for an *eight month* period for bug fixes, and for a *fourteen month* period for security issue fixes. +.. _releases-lts: + Long Term Support Versions ~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/contributing/documentation/standards.rst b/contributing/documentation/standards.rst index 2a1b10e28f5..3210ee65927 100644 --- a/contributing/documentation/standards.rst +++ b/contributing/documentation/standards.rst @@ -8,7 +8,8 @@ Sphinx ------ * The following characters are chosen for different heading levels: level 1 - is ``=``, level 2 ``-``, level 3 ``~``, level 4 ``.`` and level 5 ``"``; + is ``=`` (equal sign), level 2 ``-`` (dash), level 3 ``~`` (tilde), level 4 + ``.`` (dot) and level 5 ``"`` (double quote); * Each line should break approximately after the first word that crosses the 72nd character (so most lines end up being 72-78 characters); * The ``::`` shorthand is *preferred* over ``.. code-block:: php`` to begin a PHP @@ -50,6 +51,12 @@ Code Examples * The code follows the :doc:`Symfony Coding Standards ` as well as the `Twig Coding Standards`_; +* The code examples should look real for a web application context. Avoid abstract + or trivial examples (``foo``, ``bar``, ``demo``, etc.); +* The code should follow the :doc:`Symfony Best Practices `. + Unless the example requires a custom bundle, make sure to always use the + ``AppBundle`` bundle to store your code; +* Use ``Acme`` when the code requires a vendor name; * To avoid horizontal scrolling on code blocks, we prefer to break a line correctly if it crosses the 85th character; * When you fold one or more lines of code, place ``...`` in a comment at the point @@ -140,8 +147,12 @@ Files and Directories English Language Standards -------------------------- -* **English Dialect**: use the United States English dialect, commonly called - `American English`_. +Symfony documentation uses the United States English dialect, commonly called +`American English`_. The `American English Oxford Dictionary`_ is used as the +vocabulary reference. + +In addition, documentation follows these rules: + * **Section titles**: use a variant of the title case, where the first word is always capitalized and all other words are capitalized, except for the closed-class words (read Wikipedia article about `headings and titles`_). @@ -164,6 +175,7 @@ English Language Standards .. _`the Sphinx documentation`: http://sphinx-doc.org/rest.html#source-code .. _`Twig Coding Standards`: http://twig.sensiolabs.org/doc/coding_standards.html .. _`American English`: http://en.wikipedia.org/wiki/American_English +.. _`American English Oxford Dictionary`: http://www.oxforddictionaries.com/definition/american_english/ .. _`headings and titles`: http://en.wikipedia.org/wiki/Letter_case#Headings_and_publication_titles .. _`Serial (Oxford) Commas`: http://en.wikipedia.org/wiki/Serial_comma .. _`nosism`: http://en.wikipedia.org/wiki/Nosism diff --git a/cookbook/configuration/web_server_configuration.rst b/cookbook/configuration/web_server_configuration.rst index f246e24ee26..f5e84c7c66d 100644 --- a/cookbook/configuration/web_server_configuration.rst +++ b/cookbook/configuration/web_server_configuration.rst @@ -21,7 +21,7 @@ to use PHP :ref:`with Nginx `. static files, including images, stylesheets and JavaScript files. It is also where the front controllers live. For more details, see the :ref:`the-web-directory`. - The web directory services as the document root when configuring your + The web directory serves as the document root when configuring your web server. In the examples below, the ``web/`` directory will be the document root. This directory is ``/var/www/project/web/``. @@ -48,6 +48,12 @@ are: Allow from All + # uncomment the following lines if you install assets as symlinks + # or run into problems when compiling LESS/Sass/CoffeScript assets + # + # Option FollowSymlinks + # + ErrorLog /var/log/apache2/project_error.log CustomLog /var/log/apache2/project_access.log combined @@ -151,6 +157,12 @@ directive to pass requests for PHP files to PHP FPM: Require all granted + # uncomment the following lines if you install assets as symlinks + # or run into problems when compiling LESS/Sass/CoffeScript assets + # + # Option FollowSymlinks + # + ErrorLog /var/log/apache2/project_error.log CustomLog /var/log/apache2/project_access.log combined @@ -181,6 +193,12 @@ should look something like this: Allow from all + # uncomment the following lines if you install assets as symlinks + # or run into problems when compiling LESS/Sass/CoffeScript assets + # + # Option FollowSymlinks + # + ErrorLog /var/log/apache2/project_error.log CustomLog /var/log/apache2/project_access.log combined diff --git a/cookbook/controller/service.rst b/cookbook/controller/service.rst index 584d0ca2615..403ca08aed2 100644 --- a/cookbook/controller/service.rst +++ b/cookbook/controller/service.rst @@ -21,8 +21,10 @@ this works fine, controllers can also be specified as services. looking at the constructor arguments, it's easy to see what types of things this controller may or may not do. And because each dependency needs to be injected manually, it's more obvious (i.e. if you have many constructor - arguments) when your controller has become too big, and may need to be - split into multiple controllers. + arguments) when your controller is becoming too big. The recommendation from + the :doc:`best practices ` is also valid for + controllers defined as services: Avoid putting your business logic into the + controllers. Instead, inject services that do the bulk of the work. So, even if you don't specify your controllers as services, you'll likely see this done in some open-source Symfony bundles. It's also important @@ -122,7 +124,7 @@ the route ``_controller`` value: .. versionadded:: 2.6 If your controller service implements the ``__invoke`` method, you can simply refer to the service id - (``acme.hello.controller``). + (``app.hello_controller``). Alternatives to base Controller Methods --------------------------------------- @@ -236,6 +238,91 @@ inject *only* the exact service(s) that you need directly into the controller. are valid, exactly how you want to organize your reusable code is up to you. +Base Controller Methods and Their Service Replacements +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This list explains how to replace the convenience methods of the base +controller: + +:method:`Symfony\\Bundle\\FrameworkBundle\\Controller\\Controller::createForm` (service: ``form.factory``) + .. code-block:: php + + $formFactory->create($type, $data, $options); + +:method:`Symfony\\Bundle\\FrameworkBundle\\Controller\\Controller::createFormBuilder` (service: ``form.factory``) + .. code-block:: php + + $formFactory->createBuilder('form', $data, $options); + +:method:`Symfony\\Bundle\\FrameworkBundle\\Controller\\Controller::createNotFoundException` + .. code-block:: php + + new NotFoundHttpException($message, $previous); + +:method:`Symfony\\Bundle\\FrameworkBundle\\Controller\\Controller::forward` (service: ``http_kernel``) + .. code-block:: php + + $httpKernel->forward($controller, $path, $query); + +:method:`Symfony\\Bundle\\FrameworkBundle\\Controller\\Controller::generateUrl` (service: ``router``) + .. code-block:: php + + $router->generate($route, $params, $absolute); + +:method:`Symfony\\Bundle\\FrameworkBundle\\Controller\\Controller::getDoctrine` (service: ``doctrine``) + + *Simply inject doctrine instead of fetching it from the container* + +:method:`Symfony\\Bundle\\FrameworkBundle\\Controller\\Controller::getUser` (service: ``security.token_storage``) + .. code-block:: php + + $user = null; + $token = $tokenStorage->getToken(); + if (null !== $token && is_object($token->getUser())) { + $user = $token->getUser(); + } + +:method:`Symfony\\Bundle\\FrameworkBundle\\Controller\\Controller::isGranted` (service: ``security.authorization_checker``) + .. code-block:: php + + $authChecker->isGranted($attributes, $object); + +:method:`Symfony\\Bundle\\FrameworkBundle\\Controller\\Controller::redirect` + .. code-block:: php + + use Symfony\Component\HttpFoundation\RedirectResponse; + + return new RedirectResponse($url, $status); + +:method:`Symfony\\Bundle\\FrameworkBundle\\Controller\\Controller::render` (service: ``templating``) + .. code-block:: php + + $templating->renderResponse($view, $parameters, $response); + +:method:`Symfony\\Bundle\\FrameworkBundle\\Controller\\Controller::renderView` (service: ``templating``) + .. code-block:: php + + $templating->render($view, $parameters); + +:method:`Symfony\\Bundle\\FrameworkBundle\\Controller\\Controller::stream` (service: ``templating``) + .. code-block:: php + + use Symfony\Component\HttpFoundation\StreamedResponse; + + $templating = $this->templating; + $callback = function () use ($templating, $view, $parameters) { + $templating->stream($view, $parameters); + } + + return new StreamedResponse($callback); + +.. tip:: + + ``getRequest`` has been deprecated. Instead, have an argument to your + controller action method called ``Request $request``. The order of the + parameters is not important, but the typehint must be provided. + + .. _`Controller class source code`: https://github.com/symfony/symfony/blob/master/src/Symfony/Bundle/FrameworkBundle/Controller/Controller.php .. _`base Controller class`: https://github.com/symfony/symfony/blob/master/src/Symfony/Bundle/FrameworkBundle/Controller/Controller.php .. _`FrameworkExtraBundle documentation`: http://symfony.com/doc/current/bundles/SensioFrameworkExtraBundle/annotations/routing.html diff --git a/cookbook/doctrine/dbal.rst b/cookbook/doctrine/dbal.rst index 39cb0eabeaf..006c99371ef 100644 --- a/cookbook/doctrine/dbal.rst +++ b/cookbook/doctrine/dbal.rst @@ -35,6 +35,7 @@ To get started, configure the database connection parameters: user: root password: null charset: UTF8 + server_version: 5.6 .. code-block:: xml @@ -45,6 +46,8 @@ To get started, configure the database connection parameters: dbname="Symfony" user="root" password="null" + charset="UTF8" + server-version="5.6" driver="pdo_mysql" /> @@ -58,6 +61,8 @@ To get started, configure the database connection parameters: 'dbname' => 'Symfony', 'user' => 'root', 'password' => null, + 'charset' => 'UTF8', + 'server_version' => '5.6', ), )); diff --git a/cookbook/doctrine/file_uploads.rst b/cookbook/doctrine/file_uploads.rst index ab52ae4c940..21910b7d2d2 100644 --- a/cookbook/doctrine/file_uploads.rst +++ b/cookbook/doctrine/file_uploads.rst @@ -244,7 +244,7 @@ The following controller shows you how to handle the entire process:: $em->persist($document); $em->flush(); - return $this->redirect($this->generateUrl(...)); + return $this->redirectToRoute(...); } return array('form' => $form->createView()); @@ -267,7 +267,7 @@ in a moment to handle the file upload:: $em->persist($document); $em->flush(); - return $this->redirect(...); + return $this->redirectToRoute(...); } The ``upload()`` method will take advantage of the :class:`Symfony\\Component\\HttpFoundation\\File\\UploadedFile` @@ -432,7 +432,7 @@ call to ``$document->upload()`` should be removed from the controller:: $em->persist($document); $em->flush(); - return $this->redirect(...); + return $this->redirectToRoute(...); } .. note:: diff --git a/cookbook/doctrine/registration_form.rst b/cookbook/doctrine/registration_form.rst index 52bd31a2041..8d277cef69a 100644 --- a/cookbook/doctrine/registration_form.rst +++ b/cookbook/doctrine/registration_form.rst @@ -287,7 +287,7 @@ the validation and saves the data into the database:: $em->persist($registration->getUser()); $em->flush(); - return $this->redirect(...); + return $this->redirectToRoute(...); } return $this->render( diff --git a/cookbook/email/dev_environment.rst b/cookbook/email/dev_environment.rst index 45719625773..bf16761a78b 100644 --- a/cookbook/email/dev_environment.rst +++ b/cookbook/email/dev_environment.rst @@ -119,6 +119,8 @@ the replaced address, so you can still see who it would have been sent to. These are ``X-Swift-Cc`` and ``X-Swift-Bcc`` for the ``CC`` and ``BCC`` addresses respectively. +.. _sending-to-a-specified-address-but-with-exceptions: + Sending to a Specified Address but with Exceptions ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/cookbook/email/email.rst b/cookbook/email/email.rst index 4d97ec31b62..7a90d0626bc 100644 --- a/cookbook/email/email.rst +++ b/cookbook/email/email.rst @@ -123,7 +123,21 @@ an email is pretty straightforward:: } To keep things decoupled, the email body has been stored in a template and -rendered with the ``renderView()`` method. +rendered with the ``renderView()`` method. The ``registration.html.twig`` +template might look something like this: + +.. code-block:: html+jinja + + {# app/Resources/views/Emails/registration.html.twig #} +

You did it! You registered!

+ + {# example, assuming you have a route named "login" $} + To login, go to: .... + + Thanks! + + {# Makes an absolute URL to the /images/logo.png file #} + get('security.authorization_checker')->isGranted(new Expression( + $this->denyAccessUnlessGranted(new Expression( '"ROLE_ADMIN" in roles or (user and user.isSuperAdmin())' - ))) { - throw $this->createAccessDeniedException(); - } + )); // ... } diff --git a/cookbook/form/create_form_type_extension.rst b/cookbook/form/create_form_type_extension.rst index 9e48297c800..651d53ce849 100644 --- a/cookbook/form/create_form_type_extension.rst +++ b/cookbook/form/create_form_type_extension.rst @@ -216,7 +216,7 @@ it in the view:: */ public function configureOptions(OptionsResolver $resolver) { - $resolver->setOptional(array('image_path')); + $resolver->setDefined(array('image_path')); } /** diff --git a/cookbook/form/data_transformers.rst b/cookbook/form/data_transformers.rst index c2d5bc3294a..bfa8b472895 100644 --- a/cookbook/form/data_transformers.rst +++ b/cookbook/form/data_transformers.rst @@ -17,6 +17,11 @@ You could try to do this in your controller, but it's not the best solution. It would be better if this issue were automatically converted to an Issue object. This is where Data Transformers come into play. +.. caution:: + + When a form field has the ``inherit_data`` option set, Data Transformers + won't be applied to that field. + Creating the Transformer ------------------------ @@ -123,7 +128,9 @@ by calling ``addModelTransformer`` (or ``addViewTransformer`` - see { // ... - // this assumes that the entity manager was passed in as an option + // the "em" is an option that you pass when creating your form. Check out + // the 3rd argument to createForm in the next code block to see how this + // is passed to the form (also see setDefaultOptions). $entityManager = $options['em']; $transformer = new IssueToNumberTransformer($entityManager); @@ -140,12 +147,8 @@ by calling ``addModelTransformer`` (or ``addViewTransformer`` - see ->setDefaults(array( 'data_class' => 'Acme\TaskBundle\Entity\Task', )) - ->setRequired(array( - 'em', - )) - ->setAllowedTypes(array( - 'em' => 'Doctrine\Common\Persistence\ObjectManager', - )); + ->setRequired(array('em')) + ->setAllowedTypes('em', 'Doctrine\Common\Persistence\ObjectManager') // ... } diff --git a/cookbook/form/direct_submit.rst b/cookbook/form/direct_submit.rst index 221f7f534d8..7166210319b 100644 --- a/cookbook/form/direct_submit.rst +++ b/cookbook/form/direct_submit.rst @@ -25,7 +25,7 @@ submissions:: if ($form->isValid()) { // perform some action... - return $this->redirect($this->generateUrl('task_success')); + return $this->redirectToRoute('task_success'); } return $this->render('AcmeTaskBundle:Default:new.html.twig', array( @@ -66,7 +66,7 @@ method, pass the submitted data directly to if ($form->isValid()) { // perform some action... - return $this->redirect($this->generateUrl('task_success')); + return $this->redirectToRoute('task_success'); } } @@ -111,7 +111,7 @@ a convenient shortcut to the previous example:: if ($form->isValid()) { // perform some action... - return $this->redirect($this->generateUrl('task_success')); + return $this->redirectToRoute('task_success'); } } diff --git a/cookbook/form/form_collections.rst b/cookbook/form/form_collections.rst index 5a601c84aac..df8ca2dfa24 100644 --- a/cookbook/form/form_collections.rst +++ b/cookbook/form/form_collections.rst @@ -717,7 +717,7 @@ the relationship between the removed ``Tag`` and ``Task`` object. $em->flush(); // redirect back to some edit page - return $this->redirect($this->generateUrl('task_edit', array('id' => $id))); + return $this->redirectToRoute('task_edit', array('id' => $id)); } // render some form template diff --git a/cookbook/form/unit_testing.rst b/cookbook/form/unit_testing.rst index 7a6db8cbb6d..9148655c8fa 100644 --- a/cookbook/form/unit_testing.rst +++ b/cookbook/form/unit_testing.rst @@ -55,8 +55,7 @@ The simplest ``TypeTestCase`` implementation looks like the following:: $type = new TestedType(); $form = $this->factory->create($type); - $object = new TestObject(); - $object->fromArray($formData); + $object = TestObject::fromArray($formData); // submit the data to the form directly $form->submit($formData); diff --git a/cookbook/security/entity_provider.rst b/cookbook/security/entity_provider.rst index 54f5ec55acf..6e20607bc11 100644 --- a/cookbook/security/entity_provider.rst +++ b/cookbook/security/entity_provider.rst @@ -583,6 +583,11 @@ The code below shows the implementation of the } } +.. tip:: + + Don't forget to add the repository class to the + :ref:`mapping definition of your entity `. + To finish the implementation, the configuration of the security layer must be changed to tell Symfony to use the new custom entity provider instead of the generic Doctrine entity provider. It's trivial to achieve by removing the diff --git a/cookbook/security/form_login_setup.rst b/cookbook/security/form_login_setup.rst index 39f66f0b2ab..4d41cb5798e 100644 --- a/cookbook/security/form_login_setup.rst +++ b/cookbook/security/form_login_setup.rst @@ -76,23 +76,19 @@ First, enable form login under your firewall: Now, when the security system initiates the authentication process, it will redirect the user to the login form ``/login``. Implementing this login form visually is your job. First, create a new ``SecurityController`` inside a -bundle with an empty ``loginAction``:: +bundle:: // src/AppBundle/Controller/SecurityController.php namespace AppBundle\Controller; - use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; use Symfony\Bundle\FrameworkBundle\Controller\Controller; + use Symfony\Component\HttpFoundation\Request; class SecurityController extends Controller { - public function loginAction(Request $request) - { - // todo... - } } -Next, create two routes: one for each of the paths your configured earlier +Next, create two routes: one for each of the paths you configured earlier under your ``form_login`` configuration (``/login`` and ``/login_check``): .. configuration-block:: @@ -100,7 +96,9 @@ under your ``form_login`` configuration (``/login`` and ``/login_check``): .. code-block:: php-annotations // src/AppBundle/Controller/SecurityController.php + // ... + use Symfony\Component\HttpFoundation\Request; use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; class SecurityController extends Controller @@ -110,7 +108,6 @@ under your ``form_login`` configuration (``/login`` and ``/login_check``): */ public function loginAction(Request $request) { - // todo ... } /** @@ -118,6 +115,8 @@ under your ``form_login`` configuration (``/login`` and ``/login_check``): */ public function loginCheckAction() { + // this controller will not be executed, + // as the route is handled by the Security system } } @@ -129,6 +128,8 @@ under your ``form_login`` configuration (``/login`` and ``/login_check``): defaults: { _controller: AppBundle:Security:login } login_check: path: /login_check + # no controller is bound to this route + # as it's handled by the Security system .. code-block:: xml @@ -144,6 +145,8 @@ under your ``form_login`` configuration (``/login`` and ``/login_check``): + .. code-block:: php @@ -157,6 +160,8 @@ under your ``form_login`` configuration (``/login`` and ``/login_check``): '_controller' => 'AppBundle:Security:login', ))); $collection->add('login_check', new Route('/login_check', array())); + // no controller is bound to this route + // as it's handled by the Security system return $collection; @@ -164,7 +169,6 @@ Great! Next, add the logic to ``loginAction`` that will display the login form:: // src/AppBundle/Controller/SecurityController.php - // ... public function loginAction(Request $request) { diff --git a/cookbook/security/impersonating_user.rst b/cookbook/security/impersonating_user.rst index 8966357a198..f9003fd9b93 100644 --- a/cookbook/security/impersonating_user.rst +++ b/cookbook/security/impersonating_user.rst @@ -86,6 +86,23 @@ to show a link to exit impersonation: +In some cases you may need to get the object that represents the impersonating +user rather than the impersonated user. Use the following snippet to iterate +over the user's roles until you find one that a ``SwitchUserRole`` object:: + + use Symfony\Component\Security\Core\Role\SwitchUserRole; + + $authChecker = $this->get('security.authorization_checker'); + + if ($authChecker->isGranted('ROLE_PREVIOUS_ADMIN')) { + foreach ($authChecker->getToken()->getRoles() as $role) { + if ($role instanceof SwitchUserRole) { + $impersonatingUser = $role->getSource()->getUser(); + break; + } + } + } + Of course, this feature needs to be made available to a small group of users. By default, access is restricted to users having the ``ROLE_ALLOWED_TO_SWITCH`` role. The name of this role can be modified via the ``role`` setting. For diff --git a/cookbook/security/remember_me.rst b/cookbook/security/remember_me.rst index 4a302a16c49..93987552e68 100644 --- a/cookbook/security/remember_me.rst +++ b/cookbook/security/remember_me.rst @@ -162,19 +162,11 @@ In the following example, the action is only allowed if the user has the public function editAction() { - if (false === $this->get('security.authorization_checker')->isGranted( - 'IS_AUTHENTICATED_FULLY' - )) { - throw new AccessDeniedException(); - } + $this->denyAccessUnlessGranted('IS_AUTHENTICATED_FULLY'); // ... } -.. versionadded:: 2.6 - The ``security.authorization_checker`` service was introduced in Symfony 2.6. Prior - to Symfony 2.6, you had to use the ``isGranted()`` method of the ``security.context`` service. - If your application is based on the Symfony Standard Edition, you can also secure your controller using annotations: diff --git a/cookbook/security/securing_services.rst b/cookbook/security/securing_services.rst index f877cffd125..0b37720654a 100644 --- a/cookbook/security/securing_services.rst +++ b/cookbook/security/securing_services.rst @@ -5,41 +5,34 @@ How to Secure any Service or Method in your Application ======================================================= -In the security chapter, you can see how to :ref:`secure a controller ` -by requesting the ``security.authorization_checker`` service from the Service Container -and checking the current user's role:: +In the security chapter, you can see how to +:ref:`secure a controller ` by requesting +the ``security.authorization_checker`` service from the Service Container and +checking the current user's role:: // ... use Symfony\Component\Security\Core\Exception\AccessDeniedException; public function helloAction($name) { - if (false === $this->get('security.authorization_checker')->isGranted('ROLE_ADMIN')) { - throw new AccessDeniedException(); - } + $this->denyAccessUnlessGranted('ROLE_ADMIN'); // ... } -.. versionadded:: 2.6 - The ``security.authorization_checker`` service was introduced in Symfony 2.6. Prior - to Symfony 2.6, you had to use the ``isGranted()`` method of the ``security.context`` service. - -You can also secure *any* service in a similar way by injecting the ``security.authorization_checker`` +You can also secure *any* service by injecting the ``security.authorization_checker`` service into it. For a general introduction to injecting dependencies into services see the :doc:`/book/service_container` chapter of the book. For example, suppose you have a ``NewsletterManager`` class that sends out emails -and you want to restrict its use to only users who have some ``ROLE_NEWSLETTER_ADMIN`` -role. Before you add security, the class looks something like this: - -.. code-block:: php +and you want to restrict its use to only users who have some +``ROLE_NEWSLETTER_ADMIN`` role. Before you add security, the class looks +something like this:: // src/AppBundle/Newsletter/NewsletterManager.php namespace AppBundle\Newsletter; class NewsletterManager { - public function sendNewsletter() { // ... where you actually do the work @@ -55,8 +48,9 @@ check, this is an ideal candidate for constructor injection, which guarantees that the authorization checker object will be available inside the ``NewsletterManager`` class:: - namespace AppBundle\Newsletter; + // src/AppBundle/Newsletter/NewsletterManager.php + // ... use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface; class NewsletterManager diff --git a/cookbook/serializer.rst b/cookbook/serializer.rst index 762a0f86d19..75910f61e31 100644 --- a/cookbook/serializer.rst +++ b/cookbook/serializer.rst @@ -101,11 +101,4 @@ Here is an example on how to load the $definition->addTag('serializer.normalizer'); $container->setDefinition('get_set_method_normalizer', $definition); -.. note:: - - The :class:`Symfony\\Component\\Serializer\\Normalizer\\GetSetMethodNormalizer` - is broken by design. As soon as you have a circular object graph, an - infinite loop is created when calling the getters. You're encouraged - to add your own normalizers that fit your use-case. - .. _JMSSerializerBundle: http://jmsyst.com/bundles/JMSSerializerBundle diff --git a/cookbook/session/locale_sticky_session.rst b/cookbook/session/locale_sticky_session.rst index 3946ed85a87..239086b8e4e 100644 --- a/cookbook/session/locale_sticky_session.rst +++ b/cookbook/session/locale_sticky_session.rst @@ -116,10 +116,10 @@ before the ``FirewallListener``, which is responsible for handling authenticatio setting the user token on the ``TokenStorage``, you have no access to the user which is logged in. -Let's pretend you have defined a ``locale"`` property on your ``User`` entity -and you want to use this as the locale for the given user. To accomplish this, -you can hook into the login process and update the user's session with the -this locale value before they are redirected to their first page. +Suppose you have defined a ``locale`` property on your ``User`` entity and +you want to use this as the locale for the given user. To accomplish this, +you can hook into the login process and update the user's session with this +locale value before they are redirected to their first page. To do this, you need an event listener for the ``security.interactive_login`` event: diff --git a/quick_tour/the_controller.rst b/quick_tour/the_controller.rst index 114b2e587b3..bc90f0af99b 100644 --- a/quick_tour/the_controller.rst +++ b/quick_tour/the_controller.rst @@ -172,8 +172,10 @@ The ``hello`` action will now match URLs like ``/hello/fabien.xml`` or like ``/hello/fabien.js``, because the value of the ``_format`` variable doesn't meet its requirements. -Redirecting and Forwarding --------------------------- +.. _redirecting-and-forwarding: + +Redirecting +----------- If you want to redirect the user to another page, use the ``redirectToRoute()`` method:: @@ -193,23 +195,6 @@ method:: The ``redirectToRoute()`` method takes as arguments the route name and an optional array of parameters and redirects the user to the URL generated with those arguments. -You can also internally forward the action to another action of the same or -different controller using the ``forward()`` method:: - - // src/AppBundle/Controller/DefaultController.php - class DefaultController extends Controller - { - /** - * @Route("/", name="homepage") - */ - public function indexAction() - { - return $this->forward('AppBundle:Blog:index', array( - 'name' => $name - ); - } - } - Displaying Error Pages ---------------------- diff --git a/reference/configuration/doctrine.rst b/reference/configuration/doctrine.rst index d11044e632a..f5cc9e3dd09 100644 --- a/reference/configuration/doctrine.rst +++ b/reference/configuration/doctrine.rst @@ -60,6 +60,9 @@ Full Default Configuration driver: pdo_mysql platform_service: ~ + # the version of your database engine + server_version: ~ + # when true, queries are logged to a "doctrine" monolog channel logging: "%kernel.debug%" profiling: "%kernel.debug%" @@ -102,6 +105,9 @@ Full Default Configuration # True to use a pooled server with the oci8 driver pooled: ~ + # the version of your database engine + server_version: ~ + # Configuring MultipleActiveResultSets for the pdo_sqlsrv driver MultipleActiveResultSets: ~ @@ -202,6 +208,7 @@ Full Default Configuration charset="UTF8" logging="%kernel.debug%" platform-service="MyOwnDatabasePlatformService" + server-version="5.6" > bar string @@ -393,6 +400,7 @@ The following block shows all possible configuration keys: charset: UTF8 logging: "%kernel.debug%" platform_service: MyOwnDatabasePlatformService + server_version: 5.6 mapping_types: enum: string types: @@ -428,7 +436,8 @@ The following block shows all possible configuration keys: wrapper-class="MyDoctrineDbalConnectionWrapper" charset="UTF8" logging="%kernel.debug%" - platform-service="MyOwnDatabasePlatformService"> + platform-service="MyOwnDatabasePlatformService" + server-version="5.6"> bar string @@ -437,6 +446,17 @@ The following block shows all possible configuration keys: +.. note:: + + The ``server_version`` option was added in Doctrine DBAL 2.5, which is used + by DoctrineBundle 1.3. The value of this option should match your database + server version (use ``postgres -V`` or ``psql -V`` command to find + your PostgreSQL version and ``mysql -V`` to get your MySQL version). + + If you don't define this option and you haven't created your database yet, + you may get ``PDOException`` errors because Doctrine will try to guess the + database server version automatically and none is available. + If you want to configure multiple connections in YAML, put them under the ``connections`` key and give them a unique name: @@ -451,11 +471,13 @@ If you want to configure multiple connections in YAML, put them under the user: root password: null host: localhost + server_version: 5.6 customer: dbname: customer user: root password: null host: localhost + server_version: 5.7 The ``database_connection`` service always refers to the *default* connection, which is the first one defined or the one configured via the diff --git a/reference/configuration/framework.rst b/reference/configuration/framework.rst index 92a8cf7c1eb..1cb582b49f0 100644 --- a/reference/configuration/framework.rst +++ b/reference/configuration/framework.rst @@ -91,6 +91,24 @@ method gets called automatically. It becomes the service container parameter named ``kernel.http_method_override``. For more information, see :doc:`/cookbook/routing/method_parameters`. +.. caution:: + + If you're using the :ref:`AppCache Reverse Proxy ` + with this option, the kernel will ignore the ``_method`` parameter, + which could lead to errors. + + To fix this, invoke the ``enableHttpMethodParameterOverride()`` method + before creating the ``Request`` object:: + + // web/app.php + + // ... + $kernel = new AppCache($kernel); + + Request::enableHttpMethodParameterOverride(); // <-- add this line + $request = Request::createFromGlobals(); + // ... + ide ~~~ diff --git a/reference/configuration/swiftmailer.rst b/reference/configuration/swiftmailer.rst index 3aaf52b858a..d9614377bb3 100644 --- a/reference/configuration/swiftmailer.rst +++ b/reference/configuration/swiftmailer.rst @@ -32,6 +32,7 @@ Configuration * `threshold`_ * `sleep`_ * `delivery_address`_ +* `delivery_whitelist`_ * `disable_delivery`_ * `logging`_ @@ -156,6 +157,15 @@ emails sent during development go to a single account. This uses ``Swift_Plugins_RedirectingPlugin``. Original recipients are available on the ``X-Swift-To``, ``X-Swift-Cc`` and ``X-Swift-Bcc`` headers. +delivery_whitelist +~~~~~~~~~~~~~~~~~~ + +**type**: ``array`` + +Used in combination with ``delivery_address``. If set, emails matching any of these +patterns will be delivered like normal, instead of being sent to ``delivery_address``. +For details, see :ref:`the cookbook entry. ` + disable_delivery ~~~~~~~~~~~~~~~~ diff --git a/reference/configuration/web_profiler.rst b/reference/configuration/web_profiler.rst index 50ad25c9043..700732c7afa 100644 --- a/reference/configuration/web_profiler.rst +++ b/reference/configuration/web_profiler.rst @@ -23,10 +23,14 @@ Full default Configuration # gives you the opportunity to look at the collected data before following the redirect intercept_redirects: false + # Exclude AJAX requests in the web debug toolbar for specified paths + excluded_ajax_paths: ^/bundles|^/_wdt + .. code-block:: xml diff --git a/reference/constraints/Count.rst b/reference/constraints/Count.rst index 77cb3ac40c9..4274bab8998 100644 --- a/reference/constraints/Count.rst +++ b/reference/constraints/Count.rst @@ -89,7 +89,7 @@ you might add the following: class Participant { - public static function loadValidatorMetadata(ClassMetadata $data) + public static function loadValidatorMetadata(ClassMetadata $metadata) { $metadata->addPropertyConstraint('emails', new Assert\Count(array( 'min' => 1, diff --git a/reference/forms/types/options/data.rst.inc b/reference/forms/types/options/data.rst.inc index 9873740cf48..13afdfc44ac 100644 --- a/reference/forms/types/options/data.rst.inc +++ b/reference/forms/types/options/data.rst.inc @@ -1,7 +1,7 @@ data ~~~~ -**type**: mixed **default**: Defaults to field of the underlying object (if there is one) +**type**: ``mixed`` **default**: Defaults to field of the underlying object (if there is one) When you create a form, each field initially displays the value of the corresponding property of the form's domain object (if an object is bound diff --git a/reference/forms/types/options/inherit_data.rst.inc b/reference/forms/types/options/inherit_data.rst.inc index 9f5f1510ca8..3025e018660 100644 --- a/reference/forms/types/options/inherit_data.rst.inc +++ b/reference/forms/types/options/inherit_data.rst.inc @@ -10,3 +10,9 @@ inherit_data This option determines if the form will inherit data from its parent form. This can be useful if you have a set of fields that are duplicated across multiple forms. See :doc:`/cookbook/form/inherit_data_option`. + +.. caution:: + + When a field has the ``inherit_data`` option set, it uses the data of the + parent form as is. This means that :doc:`Data Transformers ` + won't be applied to that field.