diff --git a/book/forms.rst b/book/forms.rst index 2fd9f16b387..2e5f24d4674 100644 --- a/book/forms.rst +++ b/book/forms.rst @@ -273,21 +273,15 @@ possible paths: #. When initially loading the page in a browser, the form is simply created and rendered. :method:`Symfony\\Component\\Form\\FormInterface::handleRequest` recognizes that the form was not submitted and does nothing. - :method:`Symfony\\Component\\Form\\FormInterface::isValid` returns ``false`` + :method:`Symfony\\Component\\Form\\FormInterface::isSubmitted` returns ``false`` if the form was not submitted. #. When the user submits the form, :method:`Symfony\\Component\\Form\\FormInterface::handleRequest` recognizes this and immediately writes the submitted data back into the ``task`` and ``dueDate`` properties of the ``$task`` object. Then this object is validated. If it is invalid (validation is covered in the next section), - :method:`Symfony\\Component\\Form\\FormInterface::isValid` returns ``false`` - again, so the form is rendered together with all validation errors; - - .. note:: - - You can use the method :method:`Symfony\\Component\\Form\\FormInterface::isSubmitted` - to check whether a form was submitted, regardless of whether or not the - submitted data is actually valid. + :method:`Symfony\\Component\\Form\\FormInterface::isValid` returns + ``false``, so the form is rendered together with all validation errors; #. When the user submits the form with valid data, the submitted data is again written into the form, but this time :method:`Symfony\\Component\\Form\\FormInterface::isValid` diff --git a/book/routing.rst b/book/routing.rst index 8427eabde72..eb28b4026c3 100644 --- a/book/routing.rst +++ b/book/routing.rst @@ -1554,7 +1554,7 @@ Generating Absolute URLs ~~~~~~~~~~~~~~~~~~~~~~~~ By default, the router will generate relative URLs (e.g. ``/blog``). From -a controller, simply pass ``true`` to the third argument of the ``generateUrl()`` +a controller, simply pass ``UrlGeneratorInterface::ABSOLUTE_URL`` to the third argument of the ``generateUrl()`` method:: use Symfony\Component\Routing\Generator\UrlGeneratorInterface; diff --git a/book/templating.rst b/book/templating.rst index 96c0e36a5f7..c6aea770fde 100644 --- a/book/templating.rst +++ b/book/templating.rst @@ -1071,7 +1071,7 @@ being used and generating the correct paths accordingly. Additionally, if you use the ``asset`` function, Symfony can automatically append a query string to your asset, in order to guarantee that updated static assets won't be cached when deployed. For example, ``/images/logo.png`` might -look like ``/images/logo.png?v2``. For more information, see the :ref:`ref-framework-assets-version` +look like ``/images/logo.png?v2``. For more information, see the :ref:`reference-framework-assets-version` configuration option. .. _`book-templating-version-by-asset`: @@ -1095,7 +1095,7 @@ if you are using Twig (or the fourth argument if you are using PHP) to the desir ) ?>" alt="Symfony!" /> If you don't give a version or pass ``null``, the default package version -(from :ref:`ref-framework-assets-version`) will be used. If you pass ``false``, +(from :ref:`reference-framework-assets-version`) will be used. If you pass ``false``, versioned URL will be deactivated for this asset. If you need absolute URLs for assets, you can use the ``absolute_url`` function diff --git a/changelog.rst b/changelog.rst index ad5d7fdd86d..d18dbe0274a 100644 --- a/changelog.rst +++ b/changelog.rst @@ -13,6 +13,77 @@ documentation. Do you also want to participate in the Symfony Documentation? Take a look at the ":doc:`/contributing/documentation/overview`" article. +February, 2016 +-------------- + +New Documentation +~~~~~~~~~~~~~~~~~ + +* `#6172 `_ move assets options from templating to assets section and add base_path documentation (snoek09) +* `#6021 `_ mention routing from the database (dbu) +* `#6233 `_ Document translation_domain for choice fields (merorafael, WouterJ) +* `#5655 `_ Added doc about Homestead's Symfony integration (WouterJ) +* `#6072 `_ Add browserkit component documentation (yamiko, yamiko-ninja, robert Parker, javiereguiluz) +* `#6243 `_ Add missing getBoolean() method (bocharsky-bw) +* `#6231 `_ Use hash_equals instead of StringUtils::equals (WouterJ) +* `#5724 `_ Describe configuration behaviour with multiple mailers (xelan) +* `#6077 `_ fixes #5971 (vincentaubert) +* `#6156 `_ [reference] [form] [options] fix #6153 (HeahDude) +* `#6104 `_ Fix #6103 (zsturgess) +* `#5856 `_ Reworded the "How to use Gmail" cookbook article (javiereguiluz) +* `#6230 `_ Add annotation to glossary (rebased) (DerStoffel) +* `#5642 `_ Documented label_format option (WouterJ) + +Fixed Documentation +~~~~~~~~~~~~~~~~~~~ + +* `#5995 `_ Update dev_environment.rst (gonzalovilaseca) +* `#6240 `_ [#6224] some tweaks (xabbuh) +* `#5513 `_ [load_balancer_reverse_proxy ] Always use 127.0.0.1 as a trusted proxy (ruudk) +* `#6124 `_ [cookbook] Add annotations block and fix regex (peterkokot) + +Minor Documentation Changes +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +* `#6308 `_ fix literal syntax (xabbuh) +* `#6251 `_ To use annotations, files must be removed (pbowyer) +* `#6288 `_ Update factories.rst (velikanov) +* `#6278 `_ [HttpFoundation] Fix typo for ParameterBag getters (rendler-denis) +* `#6280 `_ Fix syntax of Company class example (cakper) +* `#6284 `_ [Book] [Routing] Fix third param true to UrlGeneratorInterface::ABSOLUTE_URI (eriwin) +* `#6269 `_ [Cookbook][Bundles]fix yaml syntax (mhor) +* `#6255 `_ [Cookbook][Doctrine] some tweaks to the Doctrine registration article (xabbuh) +* `#6229 `_ Rewrite EventDispatcher introduction (WouterJ) +* `#6260 `_ add missing options `choice_value`, `choice_name` and `choice_attr` to `EntityType` (HeahDude) +* `#6262 `_ [Form] reorder options in choice types references (HeahDude) +* `#6256 `_ Fixed code example (twifty) +* `#6250 `_ [Cookbook][Console] remove note about memory spool handling on CLI (xabbuh) +* `#6249 `_ [Cookbook][Serializer] fix wording (xabbuh) +* `#6246 `_ removed duplicate lines (seferov) +* `#6222 `_ Updated "Learn more from the Cookbook" section (sfdumi) +* `#6245 `_ [Cookbook][Console] change API doc class name (xabbuh) +* `#6223 `_ Improveme the apache/mod_php configuration example (gnat42) +* `#6234 `_ File System Security Issue in Custom Auth Article (finished) (mattjanssen, WouterJ) +* `#4773 `_ [Cookbook] Make registration_form follow best practices (xelaris) +* `#5630 `_ Add a caution about logout when using http-basic authenticated firewall (rmed19) +* `#6215 `_ Added a caution about failing cache warmers (javiereguiluz) +* `#6239 `_ Remove app_dev as build-in server is used (rmed19, WouterJ) +* `#6241 `_ [ExpressionLanguage] Add caution about backslash handling (zerustech, WouterJ) +* `#6236 `_ fix some minor typos (xabbuh) +* `#6237 `_ use literals for external class names (xabbuh) +* `#6206 `_ add separate placeholder examples for birthday, datetime and time type (snoek09) +* `#6238 `_ fix directive name (xabbuh) +* `#6224 `_ Note to create a service if you extend ExceptionController (pamuche) +* `#5958 `_ Update security.rst (mpaquet) +* `#6092 `_ Updated information about testing code coverage. (roga) +* `#6051 `_ Mention HautelookAliceBundle in best practices (theofidry, WouterJ) +* `#6220 `_ [book] fixes typo about redirect status codes in the controller chapter. (hhamon) +* `#6227 `_ Update testing.rst (dvapelnik) +* `#6212 `_ Typo in default session save_path (DerekRoth) +* `#6208 `_ Replace references of PSR-0 with PSR-4 (opdavies) +* `#6190 `_ Fix redundant command line sample (sylozof) + + January, 2016 ------------- diff --git a/components/dependency_injection/factories.rst b/components/dependency_injection/factories.rst index 55f804379e9..e97fc0f4aa6 100644 --- a/components/dependency_injection/factories.rst +++ b/components/dependency_injection/factories.rst @@ -52,7 +52,7 @@ configure the service container to use the - + .. code-block:: php diff --git a/components/event_dispatcher/introduction.rst b/components/event_dispatcher/introduction.rst index 21a96b34018..714075900f6 100644 --- a/components/event_dispatcher/introduction.rst +++ b/components/event_dispatcher/introduction.rst @@ -29,7 +29,7 @@ The Symfony EventDispatcher component implements the `Mediator`_ pattern in a simple and effective way to make all these things possible and to make your projects truly extensible. -Take a simple example from :doc:`/components/http_kernel/introduction`. +Take a simple example from :doc:`the HttpKernel component `. Once a ``Response`` object has been created, it may be useful to allow other elements in the system to modify it (e.g. add some cache headers) before it's actually used. To make this possible, the Symfony kernel throws an @@ -81,17 +81,10 @@ Naming Conventions The unique event name can be any string, but optionally follows a few simple naming conventions: -* use only lowercase letters, numbers, dots (``.``) and underscores (``_``); - -* prefix names with a namespace followed by a dot (e.g. ``kernel.``); - -* end names with a verb that indicates what action is being taken (e.g. - ``request``). - -Here are some examples of good event names: - -* ``kernel.response`` -* ``form.pre_set_data`` +* Use only lowercase letters, numbers, dots (``.``) and underscores (``_``); +* Prefix names with a namespace followed by a dot (e.g. ``order.``, ``user.*``); +* End names with a verb that indicates what action has been taken (e.g. + ``order.placed``). .. index:: single: EventDispatcher; Event subclasses @@ -105,19 +98,18 @@ contains a method for stopping :ref:`event propagation `, but not much else. +.. seealso:: + + Read ":doc:`/components/event_dispatcher/generic_event`" for more + information about this base event object. + Often times, data about a specific event needs to be passed along with the -``Event`` object so that the listeners have needed information. In the case -of the ``kernel.response`` event, the ``Event`` object that's created and -passed to each listener is actually of type -:class:`Symfony\\Component\\HttpKernel\\Event\\FilterResponseEvent`, a -subclass of the base ``Event`` object. This class contains methods such -as ``getResponse`` and ``setResponse``, allowing listeners to get or even -replace the ``Response`` object. - -The moral of the story is this: When creating a listener to an event, the -``Event`` object that's passed to the listener may be a special subclass -that has additional methods for retrieving information from and responding -to the event. +``Event`` object so that the listeners have the needed information. In such +case, a special subclass that has additional methods for retrieving and +overriding information can be passed when dispatching an event. For example, +the ``kernel.response`` event uses a +:class:`Symfony\\Component\\HttpKernel\\Event\\FilterResponseEvent`, which +contains methods to get and even replace the ``Response`` object. The Dispatcher ~~~~~~~~~~~~~~ @@ -143,20 +135,17 @@ A call to the dispatcher's ``addListener()`` method associates any valid PHP callable to an event:: $listener = new AcmeListener(); - $dispatcher->addListener('foo.action', array($listener, 'onFooAction')); + $dispatcher->addListener('acme.action', array($listener, 'onFooAction')); The ``addListener()`` method takes up to three arguments: -* The event name (string) that this listener wants to listen to; - -* A PHP callable that will be notified when an event is thrown that it listens - to; - -* An optional priority integer (higher equals more important and therefore - that the listener will be triggered earlier) that determines when a listener - is triggered versus other listeners (defaults to ``0``). If two listeners - have the same priority, they are executed in the order that they were - added to the dispatcher. +#. The event name (string) that this listener wants to listen to; +#. A PHP callable that will be executed when the specified event is dispatched; +#. An optional priority integer (higher equals more important and therefore + that the listener will be triggered earlier) that determines when a listener + is triggered versus other listeners (defaults to ``0``). If two listeners + have the same priority, they are executed in the order that they were + added to the dispatcher. .. note:: @@ -164,7 +153,7 @@ The ``addListener()`` method takes up to three arguments: ``call_user_func()`` function and returns ``true`` when passed to the ``is_callable()`` function. It can be a ``\Closure`` instance, an object implementing an ``__invoke`` method (which is what closures are in fact), - a string representing a function, or an array representing an object + a string representing a function or an array representing an object method or a class method. So far, you've seen how PHP objects can be registered as listeners. @@ -178,7 +167,7 @@ The ``addListener()`` method takes up to three arguments: Once a listener is registered with the dispatcher, it waits until the event is notified. In the above example, when the ``foo.action`` event is dispatched, -the dispatcher calls the ``AcmeListener::onFooAction`` method and passes +the dispatcher calls the ``AcmeListener::onFooAction()`` method and passes the ``Event`` object as the single argument:: use Symfony\Component\EventDispatcher\Event; @@ -193,23 +182,10 @@ the ``Event`` object as the single argument:: } } -In many cases, a special ``Event`` subclass that's specific to the given -event is passed to the listener. This gives the listener access to special -information about the event. Check the documentation or implementation of -each event to determine the exact ``Symfony\Component\EventDispatcher\Event`` -instance that's being passed. For example, the ``kernel.response`` event -passes an instance of -``Symfony\Component\HttpKernel\Event\FilterResponseEvent``:: - - use Symfony\Component\HttpKernel\Event\FilterResponseEvent; - - public function onKernelResponse(FilterResponseEvent $event) - { - $response = $event->getResponse(); - $request = $event->getRequest(); - - // ... - } +The ``$event`` argument is the event class that was passed when dispatching the +event. In many cases, a special event subclass is passed with extra +information. You can check the documentation or implementation of each event to +determine which instance is passed. .. sidebar:: Registering Event Listeners in the Service Container @@ -268,57 +244,29 @@ and dispatch your own events. This is useful when creating third-party libraries and also when you want to keep different components of your own system flexible and decoupled. -The Static ``Events`` Class -........................... - -Suppose you want to create a new Event - ``store.order`` - that is dispatched -each time an order is created inside your application. To keep things -organized, start by creating a ``StoreEvents`` class inside your application -that serves to define and document your event:: - - namespace Acme\StoreBundle; - - final class StoreEvents - { - /** - * The store.order event is thrown each time an order is created - * in the system. - * - * The event listener receives an - * Acme\StoreBundle\Event\FilterOrderEvent instance. - * - * @var string - */ - const STORE_ORDER = 'store.order'; - } - -Notice that this class doesn't actually *do* anything. The purpose of the -``StoreEvents`` class is just to be a location where information about common -events can be centralized. Notice also that a special ``FilterOrderEvent`` -class will be passed to each listener of this event. +.. _creating-an-event-object: -Creating an Event Object -........................ +Creating an Event Class +....................... -Later, when you dispatch this new event, you'll create an ``Event`` instance -and pass it to the dispatcher. The dispatcher then passes this same instance -to each of the listeners of the event. If you don't need to pass any -information to your listeners, you can use the default -``Symfony\Component\EventDispatcher\Event`` class. Most of the time, however, -you *will* need to pass information about the event to each listener. To -accomplish this, you'll create a new class that extends -``Symfony\Component\EventDispatcher\Event``. +Suppose you want to create a new event - ``order.placed`` - that is dispatched +each time a customer orders a product with your application. When dispatching +this event, you'll pass a custom event instance that has access to the placed +order. Start by creating this custom event class and documenting it:: -In this example, each listener will need access to some pretend ``Order`` -object. Create an ``Event`` class that makes this possible:: - - namespace Acme\StoreBundle\Event; + namespace Acme\Store\Event; use Symfony\Component\EventDispatcher\Event; - use Acme\StoreBundle\Order; + use Acme\Store\Order; - class FilterOrderEvent extends Event + /** + * The order.placed event is dispatched each time an order is created + * in the system. + */ + class OrderPlacedEvent extends Event { + const NAME = 'order.placed'; + protected $order; public function __construct(Order $order) @@ -332,8 +280,16 @@ object. Create an ``Event`` class that makes this possible:: } } -Each listener now has access to the ``Order`` object via the ``getOrder`` -method. +Each listener now has access to the order via the ``getOrder()`` method. + +.. note:: + + If you don't need to pass any additional data to the event listeners, you + can also use the default + :class:`Symfony\\Component\\EventDispatcher\\Event` class. In such case, + you can document the event and its name in a generic ``StoreEvents`` class, + similar to the :class:`Symfony\\Component\\HttpKernel\\KernelEvents` + class. Dispatch the Event .................. @@ -343,31 +299,20 @@ method notifies all listeners of the given event. It takes two arguments: the name of the event to dispatch and the ``Event`` instance to pass to each listener of that event:: - use Acme\StoreBundle\StoreEvents; - use Acme\StoreBundle\Order; - use Acme\StoreBundle\Event\FilterOrderEvent; + use Acme\Store\Order; + use Acme\Store\Event\OrderPlacedEvent; // the order is somehow created or retrieved $order = new Order(); // ... - // create the FilterOrderEvent and dispatch it - $event = new FilterOrderEvent($order); - $dispatcher->dispatch(StoreEvents::STORE_ORDER, $event); + // create the OrderPlacedEvent and dispatch it + $event = new OrderPlacedEvent($order); + $dispatcher->dispatch(OrderPlacedEvent::NAME, $event); -Notice that the special ``FilterOrderEvent`` object is created and passed -to the ``dispatch`` method. Now, any listener to the ``store.order`` event -will receive the ``FilterOrderEvent`` and have access to the ``Order`` object -via the ``getOrder`` method:: - - // some listener class that's been registered for "store.order" event - use Acme\StoreBundle\Event\FilterOrderEvent; - - public function onStoreOrder(FilterOrderEvent $event) - { - $order = $event->getOrder(); - // do something to or with the order - } +Notice that the special ``OrderPlacedEvent`` object is created and passed to +the ``dispatch()`` method. Now, any listener to the ``order.placed`` +event will receive the ``OrderPlacedEvent``. .. index:: single: EventDispatcher; Event subscribers @@ -386,26 +331,27 @@ subscriber is a PHP class that's able to tell the dispatcher exactly which events it should subscribe to. It implements the :class:`Symfony\\Component\\EventDispatcher\\EventSubscriberInterface` interface, which requires a single static method called -``getSubscribedEvents``. Take the following example of a subscriber that -subscribes to the ``kernel.response`` and ``store.order`` events:: +:method:`Symfony\\Component\\EventDispatcher\\EventSubscriberInterface::getSubscribedEvents`. +Take the following example of a subscriber that subscribes to the +``kernel.response`` and ``order.placed`` events:: - namespace Acme\StoreBundle\Event; + namespace Acme\Store\Event; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\HttpKernel\Event\FilterResponseEvent; - use Acme\StoreBundle\Event\FilterOrderEvent; + use Symfony\Component\HttpKernel\KernelEvents; + use Acme\Store\Event\OrderPlacedEvent; class StoreSubscriber implements EventSubscriberInterface { public static function getSubscribedEvents() { return array( - 'kernel.response' => array( + KernelEvents::RESPONSE => array( array('onKernelResponsePre', 10), - array('onKernelResponseMid', 5), - array('onKernelResponsePost', 0), + array('onKernelResponsePost', -10), ), - 'store.order' => array('onStoreOrder', 0), + OrderPlacedEvent::NAME => 'onStoreOrder', ); } @@ -414,17 +360,12 @@ subscribes to the ``kernel.response`` and ``store.order`` events:: // ... } - public function onKernelResponseMid(FilterResponseEvent $event) - { - // ... - } - public function onKernelResponsePost(FilterResponseEvent $event) { // ... } - public function onStoreOrder(FilterOrderEvent $event) + public function onStoreOrder(OrderPlacedEvent $event) { // ... } @@ -436,21 +377,22 @@ with the dispatcher, use the :method:`Symfony\\Component\\EventDispatcher\\EventDispatcher::addSubscriber` method:: - use Acme\StoreBundle\Event\StoreSubscriber; + use Acme\Store\Event\StoreSubscriber; + // ... $subscriber = new StoreSubscriber(); $dispatcher->addSubscriber($subscriber); The dispatcher will automatically register the subscriber for each event -returned by the ``getSubscribedEvents`` method. This method returns an array +returned by the ``getSubscribedEvents()`` method. This method returns an array indexed by event names and whose values are either the method name to call or an array composed of the method name to call and a priority. The example above shows how to register several listener methods for the same event in subscriber and also shows how to pass the priority of each listener method. The higher the priority, the earlier the method is called. In the above example, when the ``kernel.response`` event is triggered, the methods -``onKernelResponsePre``, ``onKernelResponseMid`` and ``onKernelResponsePost`` -are called in that order. +``onKernelResponsePre()`` and ``onKernelResponsePost()`` are called in that +order. .. index:: single: EventDispatcher; Stopping event flow @@ -467,22 +409,23 @@ the dispatcher to stop all propagation of the event to future listeners inside a listener via the :method:`Symfony\\Component\\EventDispatcher\\Event::stopPropagation` method:: - use Acme\StoreBundle\Event\FilterOrderEvent; + use Acme\Store\Event\OrderPlacedEvent; - public function onStoreOrder(FilterOrderEvent $event) + public function onStoreOrder(OrderPlacedEvent $event) { // ... $event->stopPropagation(); } -Now, any listeners to ``store.order`` that have not yet been called will +Now, any listeners to ``order.placed`` that have not yet been called will *not* be called. It is possible to detect if an event was stopped by using the :method:`Symfony\\Component\\EventDispatcher\\Event::isPropagationStopped` method which returns a boolean value:: + // ... $dispatcher->dispatch('foo.event', $event); if ($event->isPropagationStopped()) { // ... @@ -502,87 +445,9 @@ advanced usages of the ``EventDispatcher`` like dispatching other events in listeners, event chaining or even lazy loading of more listeners into the dispatcher object as shown in the following examples. -Lazy loading listeners:: - - use Symfony\Component\EventDispatcher\Event; - use Symfony\Component\EventDispatcher\EventDispatcherInterface; - use Acme\StoreBundle\Event\StoreSubscriber; - - class Foo - { - private $started = false; - - public function myLazyListener( - Event $event, - $eventName, - EventDispatcherInterface $dispatcher - ) { - if (false === $this->started) { - $subscriber = new StoreSubscriber(); - $dispatcher->addSubscriber($subscriber); - } - - $this->started = true; - - // ... more code - } - } - -Dispatching another event from within a listener:: - - use Symfony\Component\EventDispatcher\Event; - use Symfony\Component\EventDispatcher\EventDispatcherInterface; - - class Foo - { - public function myFooListener( - Event $event, - $eventName, - EventDispatcherInterface $dispatcher - ) { - $dispatcher->dispatch('log', $event); - - // ... more code - } - } - -While this above is sufficient for most uses, if your application uses multiple -``EventDispatcher`` instances, you might need to specifically inject a known -instance of the ``EventDispatcher`` into your listeners. This could be done -using constructor or setter injection as follows: - -Constructor injection:: - - use Symfony\Component\EventDispatcher\EventDispatcherInterface; - - class Foo - { - protected $dispatcher = null; - - public function __construct(EventDispatcherInterface $dispatcher) - { - $this->dispatcher = $dispatcher; - } - } - -Or setter injection:: - - use Symfony\Component\EventDispatcher\EventDispatcherInterface; - - class Foo - { - protected $dispatcher = null; - - public function setEventDispatcher(EventDispatcherInterface $dispatcher) - { - $this->dispatcher = $dispatcher; - } - } - -Choosing between the two is really a matter of taste. Many tend to prefer -the constructor injection as the objects are fully initialized at construction -time. But when you have a long list of dependencies, using setter injection -can be the way to go, especially for optional dependencies. +This can lead to some advanced applications of the ``EventDispatcher`` +including dispatching other events inside listeners, chaining events or even +lazy loading listeners into the dispatcher object. .. index:: single: EventDispatcher; Dispatcher shortcuts @@ -592,15 +457,12 @@ can be the way to go, especially for optional dependencies. Dispatcher Shortcuts ~~~~~~~~~~~~~~~~~~~~ -The :method:`EventDispatcher::dispatch ` -method always returns an :class:`Symfony\\Component\\EventDispatcher\\Event` -object. This allows for various shortcuts. For example, if one does not -need a custom event object, one can simply rely on a plain +If you do not need a custom event object, you can simply rely on a plain :class:`Symfony\\Component\\EventDispatcher\\Event` object. You do not even -need to pass this to the dispatcher as it will create one by default unless -you specifically pass one:: +need to pass this to the dispatcher as it will create one by default unless you +specifically pass one:: - $dispatcher->dispatch('foo.event'); + $dispatcher->dispatch('order.placed'); Moreover, the event dispatcher always returns whichever event object that was dispatched, i.e. either the event that was passed or the event that @@ -612,14 +474,10 @@ was created internally by the dispatcher. This allows for nice shortcuts:: Or:: - $barEvent = new BarEvent(); - $bar = $dispatcher->dispatch('bar.event', $barEvent)->getBar(); - -Or:: - - $bar = $dispatcher->dispatch('bar.event', new BarEvent())->getBar(); + $event = new OrderPlacedEvent($order); + $order = $dispatcher->dispatch('bar.event', $event)->getOrder(); -and so on... +and so on. .. index:: single: EventDispatcher; Event name introspection @@ -647,10 +505,12 @@ Other Dispatchers ----------------- Besides the commonly used ``EventDispatcher``, the component comes -with 2 other dispatchers: +with some other dispatchers: * :doc:`/components/event_dispatcher/container_aware_dispatcher` * :doc:`/components/event_dispatcher/immutable_dispatcher` +* :doc:`/components/event_dispatcher/traceable_dispatcher` (provided by the + :doc:`HttpKernel component `) .. _Mediator: https://en.wikipedia.org/wiki/Mediator_pattern .. _Closures: http://php.net/manual/en/functions.anonymous.php diff --git a/components/form/introduction.rst b/components/form/introduction.rst index 7a175581b69..e86f6b9d5a0 100644 --- a/components/form/introduction.rst +++ b/components/form/introduction.rst @@ -556,7 +556,7 @@ by ``handleRequest()`` to determine whether a form has been submitted): public function searchAction() { - $formBuilder = $this->createFormBuilder(FormType::class, null, array( + $formBuilder = $this->createFormBuilder(null, array( 'action' => '/search', 'method' => 'GET', )); diff --git a/components/http_foundation/introduction.rst b/components/http_foundation/introduction.rst index 1a925d51a66..c370c3e0ae8 100644 --- a/components/http_foundation/introduction.rst +++ b/components/http_foundation/introduction.rst @@ -140,7 +140,7 @@ has some methods to filter the input values: :method:`Symfony\\Component\\HttpFoundation\\ParameterBag::filter` Filters the parameter by using the PHP :phpfunction:`filter_var` function. -All getters takes up to three arguments: the first one is the parameter name +All getters take up to three arguments: the first one is the parameter name and the second one is the default value to return if the parameter does not exist:: diff --git a/components/serializer.rst b/components/serializer.rst index a1a6d6ed260..e63abe21cc9 100644 --- a/components/serializer.rst +++ b/components/serializer.rst @@ -363,8 +363,8 @@ Given you have the following object:: class Company { - public name; - public address; + public $name; + public $address; } And in the serialized form, all attributes must be prefixed by ``org_`` like diff --git a/cookbook/assetic/asset_management.rst b/cookbook/assetic/asset_management.rst index 9980f09b419..b3205bdaba6 100644 --- a/cookbook/assetic/asset_management.rst +++ b/cookbook/assetic/asset_management.rst @@ -555,7 +555,7 @@ done from the template and is relative to the public document root: Symfony also contains a method for cache *busting*, where the final URL generated by Assetic contains a query parameter that can be incremented via configuration on each deployment. For more information, see the - :ref:`ref-framework-assets-version` configuration option. + :ref:`reference-framework-assets-version` configuration option. .. _cookbook-assetic-dumping: diff --git a/cookbook/bundles/installation.rst b/cookbook/bundles/installation.rst index 1dd7e1f4d83..013ed4e4305 100644 --- a/cookbook/bundles/installation.rst +++ b/cookbook/bundles/installation.rst @@ -122,12 +122,12 @@ The output will look like this: .. code-block:: text assetic: - debug: %kernel.debug% + debug: '%kernel.debug%' use_controller: - enabled: %kernel.debug% + enabled: '%kernel.debug%' profiler: false - read_from: %kernel.root_dir%/../web - write_to: %assetic.read_from% + read_from: '%kernel.root_dir%/../web' + write_to: '%assetic.read_from%' java: /usr/bin/java node: /usr/local/bin/node node_paths: [] diff --git a/cookbook/console/logging.rst b/cookbook/console/logging.rst index eb6b092c547..90b7eb64f06 100644 --- a/cookbook/console/logging.rst +++ b/cookbook/console/logging.rst @@ -86,8 +86,7 @@ First configure a listener for console exception events in the service container services: kernel.listener.command_dispatch: class: AppBundle\EventListener\ConsoleExceptionListener - arguments: - logger: '@logger' + arguments: ['@logger'] tags: - { name: kernel.event_listener, event: console.exception } @@ -184,8 +183,7 @@ First configure a listener for console terminate events in the service container services: kernel.listener.command_dispatch: class: AppBundle\EventListener\ErrorLoggerListener - arguments: - logger: '@logger' + arguments: ['@logger'] tags: - { name: kernel.event_listener, event: console.terminate } diff --git a/cookbook/deployment/fortrabbit.rst b/cookbook/deployment/fortrabbit.rst new file mode 100644 index 00000000000..6b93137c8b6 --- /dev/null +++ b/cookbook/deployment/fortrabbit.rst @@ -0,0 +1,285 @@ +.. index:: + single: Deployment; Deploying to fortrabbit.com + +Deploying to fortrabbit +======================= + +This step-by-step cookbook describes how to deploy a Symfony web application to +`fortrabbit`_. You can read more about using Symfony with fortrabbit on the +official fortrabbit `Symfony install guide`_. + +Setting up fortrabbit +--------------------- + +Before getting started, you should have done a few things on the fortrabbit side: + +* `Sign up`_; +* Add an SSH key to your Account (to deploy via Git); +* Create an App. + +Preparing your Application +-------------------------- + +You don't need to change any code to deploy a Symfony application to fortrabbit. +But it requires some minor tweaks to its configuration. + +Configure Logging +~~~~~~~~~~~~~~~~~ + +Per default Symfony logs to a file. Modify the ``app/config/config_prod.yml`` file +to redirect it to :phpfunction:`error_log`: + +.. configuration-block:: + + .. code-block:: yaml + + # app/config/config_prod.yml + monolog: + # ... + handlers: + nested: + type: error_log + + .. code-block:: xml + + + + + + + + + + + + .. code-block:: php + + // app/config/config_prod.php + $container->loadFromExtension('monolog', array( + // ... + 'handlers' => array( + 'nested' => array( + 'type' => 'error_log', + ), + ), + )); + +Configuring Database Access & Session Handler +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +You can use the fortrabbit App Secrets to attain your database credentials. +Create the file ``app/config/config_prod_secrets.php`` with the following +contents:: + + // get the path to the secrects.json file + $secrets = getenv("APP_SECRETS") + if (!$secrets) { + return; + } + + // read the file and decode json to an array + $secrets = json_decode(file_get_contents($secrets), true); + + // set database parameters to the container + if (isset($secrets['MYSQL'])) { + $container->setParameter('database_driver', 'pdo_mysql'); + $container->setParameter('database_host', $secrets['MYSQL']['HOST']); + $container->setParameter('database_name', $secrets['MYSQL']['DATABASE']); + $container->setParameter('database_user', $secrets['MYSQL']['USER']); + $container->setParameter('database_password', $secrets['MYSQL']['PASSWORD']); + } + + // check if the Memcache component is present + if (isset($secrets['MEMCACHE'])) { + $memcache = $secrets['MEMCACHE']; + $handlers = []; + + foreach (range(1, $memcache['COUNT']) as $num) { + $handlers[] = $memcache['HOST'.$num].':'.$memcache['PORT'.$num]; + } + + // apply ini settings + ini_set('session.save_handler', 'memcached'); + ini_set('session.save_path', implode(',', $handlers)); + + if ("2" === $memcache['COUNT']) { + ini_set('memcached.sess_number_of_replicas', 1); + ini_set('memcached.sess_consistent_hash', 1); + ini_set('memcached.sess_binary', 1); + } + } + +Make sure this file is imported into the main config file: + +.. configuration-block:: + + .. code-block:: yaml + + # app/config/config_prod.yml + imports: + - { resource: config.yml } + - { resource: config_prod_secrets.php } + + # .. + framework: + session: + # set handler_id to null to use default session handler from php.ini (memcached) + handler_id: ~ + # .. + + .. code-block:: xml + + + + + + + + + + + + + + + + + + .. code-block:: php + + // app/config/config_prod.php + $loader->import('config/config.php'); + $loader->import('config_prod_secrets.php'); + + $container->loadFromExtension('framework', array( + 'session' => array( + 'handler_id' => null, + ), + )); + + // ... + +Configuring the Environment in the Dashboard +-------------------------------------------- + +PHP Settings +~~~~~~~~~~~~ + +The PHP version and enabled extensions are configuable under the PHP settings +of your App within the fortrabbit Dashboard. + +Environment Variables +~~~~~~~~~~~~~~~~~~~~~ + +Set the ``SYMFONY_ENV`` environment variable to ``prod`` to make sure the right +config files get loaded. ENV vars are configuable in fortrabbit Dashboard as well. + +Document Root +~~~~~~~~~~~~~ + +The document root is configuable for every custom domain you setup for your App. +The default is ``/htdocs``, but for Symfony you probably want to change it to +``/htdocs/web``. You also do so in the fortrabbit Dashboard under ``Domain`` settings. + +Deploying to fortrabbit +----------------------- + +It is assumed that your codebase is under version-control with Git and dependencies +are managed with Composer (locally). + +Every time you push to fortrabbit composer install runs before your code gets +deployed. To finetune the deployment behavior put a `fortrabbit.yml`_. deployment +file (optional) in the project root. + +Add fortrabbit as a (additional) Git remote and add your configuration changes: + +.. code-block:: bash + + $ git remote add fortrabbit git@deploy.eu2.frbit.com:.git + $ git add composer.json composer.lock + $ git add app/config/config_prod_secrets.php + +Commit and push + +.. code-block:: bash + + $ git commit -m 'fortrabbit config' + $ git push fortrabbit master -u + +.. note:: + + Replace ```` with the name of your fortrabbit App. + +.. code-block:: bash + + Commit received, starting build of branch master + + ––––––––––––––––––––––– ∙ƒ ––––––––––––––––––––––– + + B U I L D + + Checksum: + def1bb29911a62de26b1ddac6ef97fc76a5c647b + + Deployment file: + fortrabbit.yml + + Pre-script: + not found + 0ms + + Composer: + - - - + Loading composer repositories with package information + Installing dependencies (including require-dev) from lock file + Nothing to install or update + Generating autoload files + + - - - + 172ms + + Post-script: + not found + 0ms + + R E L E A S E + + Packaging: + 930ms + + Revision: + 1455788127289043421.def1bb29911a62de26b1ddac6ef97fc76a5c647b + + Size: + 9.7MB + + Uploading: + 500ms + + Build & release done in 1625ms, now queued for final distribution. + + +.. note:: + + The first ``git push`` takes much longer as all composer dependencies get + downloaded. All subsequent deploys are done within seconds. + +That's it! Your application is being deployed on fortrabbit. More information +about `database migrations and tunneling`_ can be found in the fortrabbit +documentation. + +.. _`fortrabbit`: https://www.fortrabbit.com +.. _`Symfony install guide`: https://help.fortrabbit.com/install-symfony +.. _`fortrabbit.yml`: https://help.fortrabbit.com/deployment-file-v2 +.. _`database migrations and tunneling`: https://help.fortrabbit.com/install-symfony-2#toc-migrate-amp-other-database-commands +.. _`Sign up`: https://dashboard.fortrabbit.com diff --git a/cookbook/deployment/index.rst b/cookbook/deployment/index.rst index 2b1a962fb54..f3080a413fa 100644 --- a/cookbook/deployment/index.rst +++ b/cookbook/deployment/index.rst @@ -8,3 +8,4 @@ Deployment azure-website heroku platformsh + fortrabbit \ No newline at end of file diff --git a/cookbook/doctrine/registration_form.rst b/cookbook/doctrine/registration_form.rst index 4103cf27a99..32584287daf 100644 --- a/cookbook/doctrine/registration_form.rst +++ b/cookbook/doctrine/registration_form.rst @@ -35,7 +35,7 @@ Your ``User`` entity will probably at least have the following fields: ``plainPassword`` This field is *not* persisted: (notice no ``@ORM\Column`` above it). It temporarily stores the plain password from the registration form. This field - can be validated then used to populate the ``password`` field. + can be validated and is then used to populate the ``password`` field. With some validation added, your class may look something like this:: @@ -127,7 +127,7 @@ With some validation added, your class may look something like this:: public function getSalt() { - // The bcrypt algorithm don't require a separate salt. + // The bcrypt algorithm doesn't require a separate salt. // You *may* need a real salt if you choose a different encoder. return null; } @@ -135,9 +135,10 @@ With some validation added, your class may look something like this:: // other methods, including security methods like getRoles() } -The ``UserInterface`` requires a few other methods and your ``security.yml`` file -needs to be configured properly to work with the ``User`` entity. For a more full -example, see the :ref:`Entity Provider ` article. +The :class:`Symfony\\Component\\Security\\Core\\User\\UserInterface` requires +a few other methods and your ``security.yml`` file needs to be configured +properly to work with the ``User`` entity. For a more complete example, see +the :ref:`Entity Provider ` article. .. _cookbook-registration-password-max: @@ -190,7 +191,7 @@ Next, create the form for the ``User`` entity:: public function configureOptions(OptionsResolver $resolver) { $resolver->setDefaults(array( - 'data_class' => 'AppBundle\Entity\User' + 'data_class' => 'AppBundle\Entity\User', )); } } @@ -200,7 +201,8 @@ There are just three fields: ``email``, ``username`` and ``plainPassword`` .. tip:: - To explore more things about the Form component, read :doc:`/book/forms`. + To explore more things about the Form component, read the + :doc:`chapter about forms ` in the book. Handling the Form Submission ---------------------------- @@ -212,12 +214,11 @@ into the database:: // src/AppBundle/Controller/RegistrationController.php namespace AppBundle\Controller; - use Symfony\Bundle\FrameworkBundle\Controller\Controller; - use AppBundle\Form\UserType; use AppBundle\Entity\User; - use Symfony\Component\HttpFoundation\Request; use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; + use Symfony\Bundle\FrameworkBundle\Controller\Controller; + use Symfony\Component\HttpFoundation\Request; class RegistrationController extends Controller { @@ -244,7 +245,7 @@ into the database:: $em->persist($user); $em->flush(); - // ... do any other work - like send them an email, etc + // ... do any other work - like sending them an email, etc // maybe set a "flash" success message for the user return $this->redirectToRoute('replace_with_some_route'); @@ -372,8 +373,8 @@ See :doc:`/cookbook/form/form_customization` for more details. Update your Database Schema --------------------------- -If you've updated the User entity during this tutorial, you have to update your -database schema using this command: +If you've updated the ``User`` entity during this tutorial, you have to update +your database schema using this command: .. code-block:: bash @@ -405,9 +406,9 @@ return the ``email`` property:: // ... } -Next, just update the ``providers`` section of your ``security.yml`` so that Symfony -knows to load your users via the ``email`` property on login. See -:ref:`authenticating-someone-with-a-custom-entity-provider`. +Next, just update the ``providers`` section of your ``security.yml`` file +so that Symfony knows how to load your users via the ``email`` property on +login. See :ref:`authenticating-someone-with-a-custom-entity-provider`. Adding a "accept terms" Checkbox -------------------------------- diff --git a/cookbook/doctrine/reverse_engineering.rst b/cookbook/doctrine/reverse_engineering.rst index dd50a6be9c2..b77d6609f92 100644 --- a/cookbook/doctrine/reverse_engineering.rst +++ b/cookbook/doctrine/reverse_engineering.rst @@ -99,10 +99,11 @@ The first command generates entity classes with annotation mappings. But if you want to use YAML or XML mapping instead of annotations, you should execute the second command only. -.. tip:: +.. caution:: - If you want to use annotations, you can safely delete the XML (or YAML) files - after running these two commands. + If you want to use annotations, you must remove the XML (or YAML) files + after running these two commands. This is necessary as + :ref:`it is not possible to mix mapping configuration formats ` For example, the newly created ``BlogComment`` entity class looks as follow:: diff --git a/cookbook/map.rst.inc b/cookbook/map.rst.inc index db2a2c5a680..e0d954b8965 100644 --- a/cookbook/map.rst.inc +++ b/cookbook/map.rst.inc @@ -67,6 +67,7 @@ * :doc:`/cookbook/deployment/azure-website` * :doc:`/cookbook/deployment/heroku` * :doc:`/cookbook/deployment/platformsh` + * :doc:`/cookbook/deployment/fortrabbit` * :doc:`/cookbook/doctrine/index` @@ -158,6 +159,7 @@ * :doc:`/cookbook/routing/custom_route_loader` * :doc:`/cookbook/routing/redirect_trailing_slash` * :doc:`/cookbook/routing/extra_information` + * :doc:`/cookbook/routing/routing_from_database` * :doc:`Security Authentication (Identifying/Logging in the User) ` diff --git a/cookbook/routing/index.rst b/cookbook/routing/index.rst index c42cff1748d..28b3fe97570 100644 --- a/cookbook/routing/index.rst +++ b/cookbook/routing/index.rst @@ -12,3 +12,4 @@ Routing custom_route_loader redirect_trailing_slash extra_information + routing_from_database diff --git a/cookbook/routing/routing_from_database.rst b/cookbook/routing/routing_from_database.rst new file mode 100644 index 00000000000..c63094ce944 --- /dev/null +++ b/cookbook/routing/routing_from_database.rst @@ -0,0 +1,41 @@ +.. index:: + single: Routing; Extra Information + +Looking up Routes from a Database: Symfony CMF DynamicRouter +============================================================ + +The core Symfony Routing System is excellent at handling complex sets +of routes. A highly optimized routing cache is dumped during +deployments. + +However, when working with large amounts of data that each need a nice +readable URL (e.g. for search engine optimization purposes), the routing +can get slowed down. Additionally, if routes need to be edited by users, +the route cache would need to be rebuilt frequently. + +For these cases, the ``DynamicRouter`` offers an alternative approach: + +* Routes are stored in a database; +* There is a database index on the path field, the lookup scales to huge + numbers of different routes; +* Writes only affect the index of the database, which is very efficient. + +When all routes are known during deploy time and the number is not too +high, using a :doc:`custom route loader ` is the +preferred way to add more routes. When working with just one type of +objects, a slug parameter on the object and the ``@ParamConverter`` +annotation work fine (see FrameworkExtraBundle_) . + +The ``DynamicRouter`` is useful when you need ``Route`` objects with +the full feature set of Symfony. Each route can define a specific +controller so you can decouple the URL structure from your application +logic. + +The DynamicRouter comes with built-in support for Doctrine ORM and Doctrine +PHPCR-ODM but offers the ``ContentRepositoryInterface`` to write a custom +loader, e.g. for another database type or a REST API or anything else. + +The DynamicRouter is explained in the `Symfony CMF documentation`_. + +.. _FrameworkExtraBundle: https://symfony.com/doc/current/bundles/SensioFrameworkExtraBundle/annotations/converters.html +.. _`Symfony CMF documentation`: http://symfony.com/doc/master/cmf/book/routing.html diff --git a/cookbook/security/form_login_setup.rst b/cookbook/security/form_login_setup.rst index 02b71d7c0cc..072d483bbf2 100644 --- a/cookbook/security/form_login_setup.rst +++ b/cookbook/security/form_login_setup.rst @@ -294,7 +294,7 @@ When setting up your login form, watch out for a few common pitfalls. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ First, be sure that you've defined the ``/login`` route correctly and that -it corresponds to the ``login_path`` and``check_path`` config values. +it corresponds to the ``login_path`` and ``check_path`` config values. A misconfiguration here can mean that you're redirected to a 404 page instead of the login page, or that submitting the login form does nothing (you just see the login form over and over again). diff --git a/cookbook/session/locale_sticky_session.rst b/cookbook/session/locale_sticky_session.rst index c44fa9e2544..867fc80a687 100644 --- a/cookbook/session/locale_sticky_session.rst +++ b/cookbook/session/locale_sticky_session.rst @@ -54,8 +54,8 @@ how you determine the desired locale from the request:: public static function getSubscribedEvents() { return array( - // must be registered before the default Locale listener - KernelEvents::REQUEST => array(array('onKernelRequest', 17)), + // must be registered after the default Locale listener + KernelEvents::REQUEST => array(array('onKernelRequest', 15)), ); } } diff --git a/reference/configuration/assetic.rst b/reference/configuration/assetic.rst index f4e8948b0d5..394b828b307 100644 --- a/reference/configuration/assetic.rst +++ b/reference/configuration/assetic.rst @@ -52,7 +52,7 @@ Full Default Configuration some_filter: [] workers: # see https://github.com/symfony/AsseticBundle/pull/119 - # Cache can also be busted via the framework.templating.assets_version + # Cache can also be busted via the framework.assets.version # setting - see the "framework" configuration section cache_busting: enabled: false diff --git a/reference/configuration/framework.rst b/reference/configuration/framework.rst index b881aaba378..309d5a465c6 100644 --- a/reference/configuration/framework.rst +++ b/reference/configuration/framework.rst @@ -69,19 +69,19 @@ Configuration * `gc_probability`_ * `gc_maxlifetime`_ * `save_path`_ +* `assets`_ + * `base_path`_ + * `base_urls`_ + * `packages`_ + * `version`_ + * `version_format`_ * `templating`_ - * `assets_version`_ - * `assets_version_format`_ * `hinclude_default_template`_ * :ref:`form ` * `resources`_ - * `assets_base_urls`_ - * http - * ssl * :ref:`cache ` * `engines`_ * `loaders`_ - * `packages`_ * `translator`_ * :ref:`enabled ` * `fallbacks`_ @@ -851,14 +851,175 @@ setting the value to ``null``: ), )); -templating -~~~~~~~~~~ +assets +~~~~~~ + +.. _reference-assets-base-path: + +base_path +......... + +**type**: ``string`` + +This option allows you to define a base path to be used for assets: + +.. configuration-block:: + + .. code-block:: yaml + + # app/config/config.yml + framework: + # ... + assets: + base_path: '/images' + + .. code-block:: xml + + + + + + + + + + + .. code-block:: php + + // app/config/config.php + $container->loadFromExtension('framework', array( + // ... + 'assets' => array( + 'base_path' => '/images', + ), + )); + +.. _reference-templating-base-urls: +.. _reference-assets-base-urls: + +base_urls +......... + +**type**: ``array`` + +This option allows you to define base URLs to be used for assets. +If multiple base URLs are provided, Symfony will select one from the +collection each time it generates an asset's path: + +.. configuration-block:: + + .. code-block:: yaml + + # app/config/config.yml + framework: + # ... + assets: + base_urls: + - 'http://cdn.example.com/' + + .. code-block:: xml + + + + + + + + + + + .. code-block:: php + + // app/config/config.php + $container->loadFromExtension('framework', array( + // ... + 'assets' => array( + 'base_urls' => array('http://cdn.example.com/'), + ), + )); + +packages +........ + +You can group assets into packages, to specify different base URLs for them: + +.. configuration-block:: + + .. code-block:: yaml + + # app/config/config.yml + framework: + # ... + assets: + packages: + avatars: + base_urls: 'http://static_cdn.example.com/avatars' + + .. code-block:: xml + + + + + + + + + + + + + .. code-block:: php + + // app/config/config.php + $container->loadFromExtension('framework', array( + // ... + 'assets' => array( + 'packages' => array( + 'avatars' => array( + 'base_urls' => 'http://static_cdn.example.com/avatars', + ), + ), + ), + )); + +Now you can use the ``avatars`` package in your templates: + +.. configuration-block:: php + + .. code-block:: html+twig + + + + .. code-block:: html+php + + + +Each package can configure the following options: + +* :ref:`base_path ` +* :ref:`base_urls ` +* :ref:`version ` +* :ref:`version_format ` .. _reference-framework-assets-version: .. _ref-framework-assets-version: -assets_version -.............. +version +....... **type**: ``string`` @@ -880,7 +1041,7 @@ For example, suppose you have the following: Symfony! By default, this will render a path to your image such as ``/images/logo.png``. -Now, activate the ``assets_version`` option: +Now, activate the ``version`` option: .. configuration-block:: @@ -889,7 +1050,8 @@ Now, activate the ``assets_version`` option: # app/config/config.yml framework: # ... - templating: { engines: ['twig'], assets_version: v2 } + assets: + version: 'v2' .. code-block:: xml @@ -901,10 +1063,9 @@ Now, activate the ``assets_version`` option: xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd http://symfony.com/schema/dic/symfony http://symfony.com/schema/dic/symfony/symfony-1.0.xsd"> - - - twig - + + + .. code-block:: php @@ -912,40 +1073,40 @@ Now, activate the ``assets_version`` option: // app/config/config.php $container->loadFromExtension('framework', array( // ... - 'templating' => array( - 'engines' => array('twig'), - 'assets_version' => 'v2', + 'assets' => array( + 'version' => 'v2', ), )); Now, the same asset will be rendered as ``/images/logo.png?v2`` If you use -this feature, you **must** manually increment the ``assets_version`` value +this feature, you **must** manually increment the ``version`` value before each deployment so that the query parameters change. It's also possible to set the version value on an asset-by-asset basis (instead of using the global version - e.g. ``v2`` - set here). See :ref:`Versioning by Asset ` for details. -You can also control how the query string works via the `assets_version_format`_ +You can also control how the query string works via the `version_format`_ option. .. tip:: As with all settings, you can use a parameter as value for the - ``assets_version``. This makes it easier to increment the cache on each + ``version``. This makes it easier to increment the cache on each deployment. .. _reference-templating-version-format: +.. _reference-assets-version-format: -assets_version_format -..................... +version_format +.............. **type**: ``string`` **default**: ``%%s?%%s`` This specifies a :phpfunction:`sprintf` pattern that will be used with the -`assets_version`_ option to construct an asset's path. By default, the pattern +`version`_ option to construct an asset's path. By default, the pattern adds the asset's version as a query string. For example, if -``assets_version_format`` is set to ``%%s?version=%%s`` and ``assets_version`` +``version_format`` is set to ``%%s?version=%%s`` and ``version`` is set to ``5``, the asset's path would be ``/images/logo.png?version=5``. .. note:: @@ -958,7 +1119,7 @@ is set to ``5``, the asset's path would be ``/images/logo.png?version=5``. Some CDN's do not support cache-busting via query strings, so injecting the version into the actual file path is necessary. Thankfully, - ``assets_version_format`` is not limited to producing versioned query + ``version_format`` is not limited to producing versioned query strings. The pattern receives the asset's original path and version as its first @@ -974,6 +1135,9 @@ is set to ``5``, the asset's path would be ``/images/logo.png?version=5``. any URL rewriting. The latter option is useful if you would like older asset versions to remain accessible at their original URL. +templating +~~~~~~~~~~ + hinclude_default_template ......................... @@ -1061,118 +1225,6 @@ Assume you have custom global form themes in See :ref:`book-forms-theming-global` for more information. -.. _reference-templating-base-urls: - -assets_base_urls -................ - -**default**: ``{ http: [], ssl: [] }`` - -This option allows you to define base URLs to be used for assets referenced -from ``http`` and ``ssl`` (``https``) pages. If multiple base URLs are -provided, Symfony will select one from the collection each time it generates -an asset's path: - -.. configuration-block:: - - .. code-block:: yaml - - # app/config/config.yml - framework: - # ... - templating: - assets_base_urls: - http: - - 'http://cdn.example.com/' - # you can also pass just a string: - # assets_base_urls: - # http: '//cdn.example.com/' - - .. code-block:: xml - - - - - - - - - - - http://cdn.example.com/ - - - - - - .. code-block:: php - - // app/config/config.php - $container->loadFromExtension('framework', array( - // ... - 'templating' => array( - 'assets_base_urls' => array( - 'http' => array( - 'http://cdn.example.com/', - ), - ), - // you can also pass just a string: - // 'assets_base_urls' => array( - // 'http' => '//cdn.example.com/', - // ), - ), - )); - -For your convenience, you can pass a string or array of strings to -``assets_base_urls`` directly. This will automatically be organized into -the ``http`` and ``ssl`` base urls (``https://`` and `protocol-relative`_ -URLs will be added to both collections and ``http://`` only to the ``http`` -collection): - -.. configuration-block:: - - .. code-block:: yaml - - # app/config/config.yml - framework: - # ... - templating: - assets_base_urls: - - '//cdn.example.com/' - # you can also pass just a string: - # assets_base_urls: '//cdn.example.com/' - - .. code-block:: xml - - - - - - - - - - //cdn.example.com/ - - - - - .. code-block:: php - - // app/config/config.php - $container->loadFromExtension('framework', array( - // ... - 'templating' => array( - 'assets_base_urls' => array( - '//cdn.example.com/', - ), - // you can also pass just a string: - // 'assets_base_urls' => '//cdn.example.com/', - ), - )); - .. _reference-templating-cache: cache @@ -1208,78 +1260,6 @@ templating loaders. Templating loaders are used to find and load templates from a resource (e.g. a filesystem or database). Templating loaders must implement :class:`Symfony\\Component\\Templating\\Loader\\LoaderInterface`. -packages -........ - -You can group assets into packages, to specify different base URLs for them: - -.. configuration-block:: - - .. code-block:: yaml - - # app/config/config.yml - framework: - # ... - templating: - packages: - avatars: - base_urls: 'http://static_cdn.example.com/avatars' - - .. code-block:: xml - - - - - - - - - - - - - - - - - .. code-block:: php - - // app/config/config.php - $container->loadFromExtension('framework', array( - // ... - 'templating' => array( - 'packages' => array( - 'avatars' => array( - 'base_urls' => 'http://static_cdn.example.com/avatars', - ), - ), - ), - )); - -Now you can use the ``avatars`` package in your templates: - -.. configuration-block:: php - - .. code-block:: html+twig - - - - .. code-block:: html+php - - - -Each package can configure the following options: - -* :ref:`base_urls ` -* :ref:`version ` -* :ref:`version_format ` - translator ~~~~~~~~~~ @@ -1612,34 +1592,35 @@ Full Default Configuration serializer: enabled: false + # assets configuration + assets: + base_path: ~ + base_urls: [] + version: ~ + version_format: '%%s?%%s' + packages: + + # Prototype + name: + base_path: ~ + base_urls: [] + version: ~ + version_format: '%%s?%%s' + # templating configuration templating: - assets_version: ~ - assets_version_format: '%%s?%%s' hinclude_default_template: ~ form: resources: # Default: - FrameworkBundle:Form - assets_base_urls: - http: [] - ssl: [] cache: ~ engines: # Required # Example: - twig loaders: [] - packages: - - # Prototype - name: - version: ~ - version_format: '%%s?%%s' - base_urls: - http: [] - ssl: [] # translator configuration translator: @@ -1660,7 +1641,6 @@ Full Default Configuration file_cache_dir: '%kernel.cache_dir%/annotations' debug: '%kernel.debug%' -.. _`protocol-relative`: http://tools.ietf.org/html/rfc3986#section-4.2 .. _`HTTP Host header attacks`: http://www.skeletonscribe.net/2013/05/practical-http-host-header-attacks.html .. _`Security Advisory Blog post`: https://symfony.com/blog/security-releases-symfony-2-0-24-2-1-12-2-2-5-and-2-3-3-released#cve-2013-4752-request-gethost-poisoning .. _`Doctrine Cache`: http://docs.doctrine-project.org/projects/doctrine-common/en/latest/reference/caching.html diff --git a/reference/forms/types/choice.rst b/reference/forms/types/choice.rst index 6b227a4e12f..240e3f46ab9 100644 --- a/reference/forms/types/choice.rst +++ b/reference/forms/types/choice.rst @@ -13,19 +13,19 @@ To use this field, you must specify *either* ``choices`` or ``choice_loader`` op | Rendered as | can be various tags (see below) | +-------------+------------------------------------------------------------------------------+ | Options | - `choices`_ | -| | - `choices_as_values`_ | -| | - `choice_loader`_ | -| | - `choice_label`_ | | | - `choice_attr`_ | +| | - `choice_label`_ | +| | - `choice_list`_ (deprecated) | +| | - `choice_loader`_ | +| | - `choice_name`_ | | | - `choice_translation_domain`_ | -| | - `placeholder`_ | +| | - `choice_value`_ | +| | - `choices_as_values`_ | | | - `expanded`_ | +| | - `group_by`_ | | | - `multiple`_ | +| | - `placeholder`_ | | | - `preferred_choices`_ | -| | - `group_by`_ | -| | - `choice_value`_ | -| | - `choice_name`_ | -| | - `choice_list`_ (deprecated) | +-------------+------------------------------------------------------------------------------+ | Overridden | - `compound`_ | | options | - `empty_data`_ | @@ -185,83 +185,12 @@ is the item's label and the array value is the item's value:: 'choices_as_values' => true, )); -choices_as_values -~~~~~~~~~~~~~~~~~ - -**type**: ``boolean`` **default**: false - -.. versionadded:: 2.7 - - The ``choices_as_values`` option was introduced in Symfony 2.7. - -The ``choices_as_values`` option was added to keep backward compatibility with the -*old* way of handling the ``choices`` option. When set to ``false`` (or omitted), -the choice keys are used as the underlying value and the choice values are shown -to the user. - -* Before 2.7 (and deprecated now):: - - $builder->add('gender', 'choice', array( - // Shows "Male" to the user, returns "m" when selected - 'choices' => array('m' => 'Male', 'f' => 'Female'), - // before 2.7, this option didn't actually exist, but the - // behavior was equivalent to setting this to false in 2.7. - 'choices_as_values' => false, - )); - -* Since 2.7:: - - $builder->add('gender', ChoiceType::class, array( - // Shows "Male" to the user, returns "m" when selected - 'choices' => array('Male' => 'm', 'Female' => 'f'), - 'choices_as_values' => true, - )); - -In Symfony 3.0, the ``choices_as_values`` option doesn't exist, but the ``choice`` -type behaves as if it were set to true: - -* Default for 3.0:: - - $builder->add('gender', ChoiceType::class, array( - 'choices' => array('Male' => 'm', 'Female' => 'f'), - )); - -choice_loader -~~~~~~~~~~~~~ - -.. versionadded:: 2.7 - - The ``choice_loader`` option was added in Symfony 2.7. - -**type**: :class:`Symfony\\Component\\Form\\ChoiceList\\Loader\\ChoiceLoaderInterface` - -The ``choice_loader`` can be used to only partially load the choices in cases where -a fully-loaded list is not necessary. This is only needed in advanced cases and -would replace the ``choices`` option. +.. include:: /reference/forms/types/options/choice_attr.rst.inc .. _reference-form-choice-label: .. include:: /reference/forms/types/options/choice_label.rst.inc -.. include:: /reference/forms/types/options/choice_attr.rst.inc - -.. include:: /reference/forms/types/options/placeholder.rst.inc - -.. include:: /reference/forms/types/options/choice_translation_domain.rst.inc - -.. include:: /reference/forms/types/options/expanded.rst.inc - -.. include:: /reference/forms/types/options/multiple.rst.inc - -.. include:: /reference/forms/types/options/preferred_choices.rst.inc - -.. include:: /reference/forms/types/options/group_by.rst.inc - -.. include:: /reference/forms/types/options/choice_value.rst.inc - -.. include:: /reference/forms/types/options/choice_name.rst.inc - - choice_list ~~~~~~~~~~~ @@ -293,6 +222,8 @@ For example:: The ``status`` field created by the code above will be rendered as: +.. code-block:: html + .. code-block:: html