Skip to content

Commit 013f3cc

Browse files
committed
Merge branch '5.4' into 6.2
* 5.4: [Form] Removed jQuery in favour of vanilla Javascript [HttpCache] Explain how to extend the HttpCache class
2 parents 86dd45f + e217f00 commit 013f3cc

File tree

2 files changed

+55
-110
lines changed

2 files changed

+55
-110
lines changed

http_cache/cache_invalidation.rst

Lines changed: 55 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,9 @@ the word "PURGE" is a convention, technically this can be any string) instead
4747
of ``GET`` and make the cache proxy detect this and remove the data from the
4848
cache instead of going to the application to get a response.
4949

50-
Here is how you can configure the Symfony reverse proxy (See :doc:`/http_cache`)
51-
to support the ``PURGE`` HTTP method::
50+
Here is how you can configure the :ref:`Symfony reverse proxy <symfony-gateway-cache>`
51+
to support the ``PURGE`` HTTP method. First create a caching kernel that overrides the
52+
:method:`Symfony\\Component\\HttpKernel\\HttpCache\\HttpCache::invalidate` method::
5253

5354
// src/CacheKernel.php
5455
namespace App;
@@ -84,6 +85,58 @@ to support the ``PURGE`` HTTP method::
8485
}
8586
}
8687

88+
Then, register the class as a service that :doc:`decorates </service_container/service_decoration>`
89+
``http_cache``::
90+
91+
.. configuration-block::
92+
93+
.. code-block:: yaml
94+
95+
# config/services.yaml
96+
services:
97+
App\CacheKernel:
98+
decorates: http_cache
99+
arguments:
100+
- '@kernel'
101+
- '@http_cache.store'
102+
- '@?esi'
103+
104+
.. code-block:: xml
105+
106+
<!-- config/services.xml -->
107+
<?xml version="1.0" encoding="UTF-8" ?>
108+
<container xmlns="http://symfony.com/schema/dic/services"
109+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
110+
xsi:schemaLocation="http://symfony.com/schema/dic/services
111+
https://symfony.com/schema/dic/services/services-1.0.xsd"
112+
>
113+
<service id="App\CacheKernel" decorates="http_cache">
114+
<argument type="service" id="kernel"/>
115+
<argument type="service" id="http_cache.store"/>
116+
<argument type="service" id="esi" on-invalid="null"/>
117+
</service>
118+
</container>
119+
120+
.. code-block:: php
121+
122+
// config/services.php
123+
namespace Symfony\Component\DependencyInjection\Loader\Configurator;
124+
125+
use App\CacheKernel;
126+
127+
return function (ContainerConfigurator $containerConfigurator) {
128+
$services = $containerConfigurator->services();
129+
130+
$services->set(CacheKernel::class)
131+
->decorate('http_cache')
132+
->args([
133+
service('kernel'),
134+
service('http_cache.store'),
135+
service('esi')->nullOnInvalid(),
136+
])
137+
;
138+
};
139+
87140
.. caution::
88141

89142
You must protect the ``PURGE`` HTTP method somehow to avoid random people

reference/forms/types/collection.rst

Lines changed: 0 additions & 108 deletions
Original file line numberDiff line numberDiff line change
@@ -86,114 +86,6 @@ existing addresses. Adding new addresses is possible by using the `allow_add`_
8686
option (and optionally the `prototype`_ option) (see example below). Removing
8787
emails from the ``emails`` array is possible with the `allow_delete`_ option.
8888

89-
Adding and Removing Items
90-
~~~~~~~~~~~~~~~~~~~~~~~~~
91-
92-
If `allow_add`_ is set to ``true``, then if any unrecognized items are submitted,
93-
they'll be added seamlessly to the array of items. This is great in theory,
94-
but takes a little bit more effort in practice to get the client-side JavaScript
95-
correct.
96-
97-
Following along with the previous example, suppose you start with two
98-
emails in the ``emails`` data array. In that case, two input fields will
99-
be rendered that will look something like this (depending on the name of
100-
your form):
101-
102-
.. code-block:: html
103-
104-
<input type="email" id="form_emails_0" name="form[emails][0]" value="foo@foo.com"/>
105-
<input type="email" id="form_emails_1" name="form[emails][1]" value="bar@bar.com"/>
106-
107-
To allow your user to add another email, just set `allow_add`_ to ``true``
108-
and - via JavaScript - render another field with the name ``form[emails][2]``
109-
(and so on for more and more fields).
110-
111-
To help make this easier, setting the `prototype`_ option to ``true`` allows
112-
you to render a "template" field, which you can then use in your JavaScript
113-
to help you dynamically create these new fields. A rendered prototype field
114-
will look like this:
115-
116-
.. code-block:: html
117-
118-
<input type="email"
119-
id="form_emails___name__"
120-
name="form[emails][__name__]"
121-
value=""
122-
/>
123-
124-
By replacing ``__name__`` with some unique value (e.g. ``2``),
125-
you can build and insert new HTML fields into your form.
126-
127-
Using jQuery, a simple example might look like this. If you're rendering
128-
your collection fields all at once (e.g. ``form_row(form.emails)``), then
129-
things are even easier because the ``data-prototype`` attribute is rendered
130-
automatically for you (with a slight difference - see note below) and all
131-
you need is this JavaScript code:
132-
133-
.. code-block:: javascript
134-
135-
// add-collection-widget.js
136-
jQuery(document).ready(function () {
137-
jQuery('.add-another-collection-widget').click(function (e) {
138-
var list = jQuery(jQuery(this).attr('data-list-selector'));
139-
// Try to find the counter of the list or use the length of the list
140-
var counter = list.data('widget-counter') || list.children().length;
141-
142-
// grab the prototype template
143-
var newWidget = list.attr('data-prototype');
144-
// replace the "__name__" used in the id and name of the prototype
145-
// with a number that's unique to your emails
146-
// end name attribute looks like name="contact[emails][2]"
147-
newWidget = newWidget.replace(/__name__/g, counter);
148-
// Increase the counter
149-
counter++;
150-
// And store it, the length cannot be used if deleting widgets is allowed
151-
list.data('widget-counter', counter);
152-
153-
// create a new list element and add it to the list
154-
var newElem = jQuery(list.attr('data-widget-tags')).html(newWidget);
155-
newElem.appendTo(list);
156-
});
157-
});
158-
159-
And update the template as follows:
160-
161-
.. code-block:: html+twig
162-
163-
{{ form_start(form) }}
164-
{# ... #}
165-
166-
{# store the prototype on the data-prototype attribute #}
167-
<ul id="email-fields-list"
168-
data-prototype="{{ form_widget(form.emails.vars.prototype)|e }}"
169-
data-widget-tags="{{ '<li></li>'|e }}"
170-
data-widget-counter="{{ form.emails|length }}">
171-
{% for emailField in form.emails %}
172-
<li>
173-
{{ form_errors(emailField) }}
174-
{{ form_widget(emailField) }}
175-
</li>
176-
{% endfor %}
177-
</ul>
178-
179-
<button type="button"
180-
class="add-another-collection-widget"
181-
data-list-selector="#email-fields-list">Add another email</button>
182-
183-
{# ... #}
184-
{{ form_end(form) }}
185-
186-
<script src="add-collection-widget.js"></script>
187-
188-
.. tip::
189-
190-
If you're rendering the entire collection at once, then the prototype
191-
is automatically available on the ``data-prototype`` attribute of the
192-
element (e.g. ``div`` or ``table``) that surrounds your collection.
193-
The only difference is that the entire "form row" is rendered for you,
194-
meaning you wouldn't have to wrap it in any container element as it
195-
was done above.
196-
19789
Field Options
19890
-------------
19991

0 commit comments

Comments
 (0)