8000 Merge branch '4.0' · symfony/symfony-docs@0ba3d9f · GitHub
[go: up one dir, main page]

Skip to content
10000

Commit 0ba3d9f

Browse files
committed
Merge branch '4.0'
* 4.0: (23 commits) Missing a dot in the last block of code adding note to config Add "url" key in dbal configuration Update console.rst Update the_architecture.rst Fixed the internal references of the serializer docs Minor code correction in guard authentication. fix typo Update override.rst Minor reword Update database.rst Changed symfony/web-server-bundle to dev package update to translatorInterface Review Typo fix: use correct parameter `options` Tipfeler required -> require [Serializer] Add docs for attributes context key Fix docs about making external requests with BrowserKit remove CompilerPassInterface from kernel Fix path in configuration/environments.rst ...
2 parents 0561864 + 13d112b commit 0ba3d9f

File tree

16 files changed

+348
-35
lines changed

16 files changed

+348
-35
lines changed

bundles/override.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ to a new validation group:
101101

102102
.. code-block:: yaml
103103
104-
# src/Acme/UserBundle/Resources/config/validation.yaml
104+
# config/validator/validation.yaml
105105
FOS\UserBundle\Model\User:
106106
properties:
107107
plainPassword:
@@ -114,7 +114,7 @@ to a new validation group:
114114
115115
.. code-block:: xml
116116
117-
<!-- src/Acme/UserBundle/Resources/config/validation.xml -->
117+
<!-- config/validator/validation.xml -->
118118
<?xml version="1.0" encoding="UTF-8" ?>
119119
<constraint-mapping xmlns="http://symfony.com/schema/dic/constraint-mapping"
120120
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

components/browser_kit.rst

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,12 @@ The BrowserKit Component
88
The BrowserKit component simulates the behavior of a web browser, allowing
99
you to make requests, click on links and submit forms programmatically.
1010

11+
.. note::
12+
13+
The BrowserKit component can only make internal requests to your application.
14+
If you need to make requests to external sites and applications, consider
15+
using `Goutte`_, a simple web scraper based on Symfony Components.
16+
1117
Installation
1218
------------
1319

@@ -60,7 +66,7 @@ URL::
6066
use Acme\Client;
6167

6268
$client = new Client();
63-
$crawler = $client->request('GET', 'http://symfony.com');
69+
$crawler = $client->request('GET', '/');
6470

6571
The value returned by the ``request()`` method is an instance of the
6672
:class:`Symfony\\Component\\DomCrawler\\Crawler` class, provided by the
@@ -78,7 +84,7 @@ performs the needed HTTP GET request to simulate the link click::
7884
use Acme\Client;
7985

8086
$client = new Client();
81-
$crawler = $client->request('GET', 'http://symfony.com');
87+
$crawler = $client->request('GET', '/product/123');
8288
$link = $crawler->selectLink('Go elsewhere...')->link();
8389
$client->click($link);
8490

@@ -120,7 +126,7 @@ retrieve any cookie while making requests with the client::
120126

121127
// Make a request
122128
$client = new Client();
123-
$crawler = $client->request('GET', 'http://symfony.com');
129+
$crawler = $client->request('GET', '/');
124130

125131
// Get the cookie Jar
126132
$cookieJar = $client->getCookieJar();
@@ -153,7 +159,7 @@ Looping Through Cookies
153159
154160
// Make a request
155161
$client = new Client();
156-
$crawler = $client->request('GET', 'http://symfony.com');
162+
$crawler = $client->request('GET', '/');
157163
158164
// Get the cookie Jar
159165
$cookieJar = $client->getCookieJar();
@@ -199,9 +205,8 @@ history::
199205

200206
use Acme\Client;
201207

202-
// make a real request to an external site
203208
$client = new Client();
204-
$client->request('GET', 'http://symfony.com');
209+
$client->request('GET', '/');
205210

206211
// select and click on a link
207212
$link = $crawler->selectLink('Documentation')->link();
@@ -218,9 +223,8 @@ also delete all the cookies::
218223

219224
use Acme\Client;
220225

221-
// make a real request to an external site
222226
$client = new Client();
223-
$client->request('GET', 'http://symfony.com');
227+
$client->request('GET', '/');
224228

225229
// delete history
226230
$client->restart();

components/lock.rst

Lines changed: 258 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,258 @@
1+
.. index::
2+
single: Lock
3+
single: Components; Lock
4+
5+
The Lock Component
6+
==================
7+
8+
The Lock Component creates and manages `locks`_, a mechanism to provide
9+
exclusive access to a shared resource.
10+
11+
.. versionadded:: 3.4
12+
The Lock component was introduced in Symfony 3.4.
13+
14+
Installation
15+
------------
16+
17+
You can install the component in 2 different ways:
18+
19+
* :doc:`Install it via Composer </components/using_components>` (``symfony/lock`` on `Packagist`_);
20+
* Use the official Git repository (https://github.com/symfony/lock).
21+
22+
.. include:: /components/require_autoload.rst.inc
23+
24+
Usage
25+
-----
26+
27+
Locks are used to guarantee exclusive access to some shared resource. In
28+
Symfony applications, you can use locks for example to ensure that a command is
29+
not executed more than once at the same time (on the same or different servers).
30+
31+
In order to manage the state of locks, a ``Store`` needs to be created first
32+
and then use the :class:`Symfony\\Component\\Lock\\Factory` class to actually
33+
create the lock for some resource::
34+
35+
use Symfony\Component\Lock\Factory;
36+
use Symfony\Component\Lock\Store\SemaphoreStore;
37+
38+
$store = new SemaphoreStore();
39+
$factory = new Factory($store);
40+
41+
Then, a call to the :method:`Symfony\\Component\\Lock\\LockInterface::acquire`
42+
method will try to acquire the lock. Its first argument is an arbitrary string
43+
that represents the locked resource::
44+
45+
// ...
46+
$lock = $factory->createLock('pdf-invoice-generation');
47+
48+
if ($lock->acquire()) {
49+
// The resource "pdf-invoice-generation" is locked.
50+
// You can compute and generate invoice safely here.
51+
52+
$lock->release();
53+
}
54+
55+
If the lock can not be acquired, the method returns ``false``. The ``acquire()``
56+
method can be safely called repeatedly, even if the lock is already acquired.
57+
58+
.. note::
59+
60+
Unlike other implementations, the Lock Component distinguishes locks
61+
instances even when they are created for the same resource. If a lock has
62+
to be used by several services, they should share the same ``Lock`` instance
63+
returned by the ``Factory::createLock`` method.
64+
65+
Blocking Locks
66+
--------------
67+
68+
By default, when a lock cannot be acquired, the ``acquire`` method returns
69+
``false`` immediately. To wait (indefinitely) until the lock
70+
can be created, pass ``true`` as the argument of the ``acquire()`` method. This
71+
is called a **blocking lock** because the execution of your application stops
72+
until the lock is acquired.
73+
74+
Some of the built-in ``Store`` classes support this feature. When they don't,
75+
they can be decorated with the ``RetryTillSaveStore`` class::
76+
77+
use Symfony\Component\Lock\Factory;
78+
use Symfony\Component\Lock\Store\RedisStore;
79+
use Symfony\Component\Lock\Store\RetryTillSaveStore;
80+
81+
$store = new RedisStore(new \Predis\Client('tcp://localhost:6379'));
82+
$store = new RetryTillSaveStore($store);
83+
$factory = new Factory($store);
84+
85+
$lock = $factory->createLock('notification-flush');
86+
$lock->acquire(true);
87+
88+
Expiring Locks
89+
--------------
90+
91+
Locks created remotely are difficult to manage because there is no way for the
92+
remote ``Store`` to know if the locker process is still alive. Due to bugs,
93+
fatal errors or segmentation faults, it cannot be guaranteed that ``release()``
94+
method will be called, which would cause the resource to be locked infinitely.
95+
96+
The best solution in those cases is to create **expiring locks**, which are
97+
released automatically after some amount of time has passed (called TTL for
98+
*Time To Live*). This time, in seconds, is configured as the second argument of
99+
the ``createLock()`` method. If needed, these locks can also be released early
100+
with the ``release()`` method.
101+
102+
The trickiest part when working with expiring locks is choosing the right TTL.
103+
If it's too short, other processes could acquire the lock before finishing the
104+
job; it it's too long and the process crashes before calling the ``release()``
105+
method, the resource will stay locked until the timeout::
106+
107+
// ...
108+
// create an expiring lock that lasts 30 seconds
109+
$lock = $factory->createLock('charts-generation', 30);
110+
111+
$lock->acquire();
112+
try {
113+
// perform a job during less than 30 seconds
114+
} finally {
115+
$lock->release();
116+
}
117+
118+
.. tip::
119+
120+
To avoid letting the lock in a locking state, it's recommended to wrap the
121+
job in a try/catch/finally block to always try to release the expiring lock.
122+
123+
In case of long-running tasks, it's better to start with a not too long TTL and
124+
then use the :method:`Symfony\\Component\\Lock\\LockInterface::refresh` method
125+
to reset the TTL to its original value::
126+
127+
// ...
128+
$lock = $factory->createLock('charts-generation', 30);
129+
130+
$lock->acquire();
131+
try {
132+
while (!$finished) {
133+
// perform a small part of the job.
134+
135+
// renew the lock for 30 more seconds.
136+
$lock->refresh();
137+
}
138+
} finally {
139+
$lock->release();
140+
}
141+
142+
Available Stores
143+
----------------
144+
145+
Locks are created and managed in ``Stores``, which are classes that implement
146+
:class:`Symfony\\Component\\Lock\\StoreInterface`. The component includes the
147+
following built-in store types:
148+
149+
150+
============================================ ====== ======== ========
151+
Store Scope Blocking Expiring
152+
============================================ ====== ======== ========
153+
:ref:`FlockStore <lock-store-flock>` local yes no
154+
:ref:`MemcachedStore <lock-store-memcached>` remote no yes
155+
:ref:`RedisStore <lock-store-redis>` remote no yes
156+
:ref:`SemaphoreStore <lock-store-semaphore>` local yes no
157+
============================================ ====== ======== ========
158+
159+
.. _lock-store-flock:
160+
161+
FlockStore
162+
~~~~~~~~~~
163+
164+
The FlockStore uses the file system on the local computer to create the locks.
165+
It does not support expiration, but the lock is automatically released when the
166+
PHP process is terminated::
167+
168+
use Symfony\Component\Lock\Store\FlockStore;
169+
170+
// the argument is the path of the directory where the locks are created
171+
$store = new FlockStore(sys_get_temp_dir());
172+
173+
.. caution::
174+
175+
Beware that some file systems (such as some types of NFS) do not support
176+
locking. In those cases, it's better to use a directory on a local disk
177+
drive or a remote store based on Redis or Memcached.
178+
179+
.. _lock-store-memcached:
180+
181+
MemcachedStore
182+
~~~~~~~~~~~~~~
183+
184+
The MemcachedStore saves locks on a Memcached server, it requires a Memcached
185+
connection implementing the ``\Memcached`` class. This store does not
186+
support blocking, and expects a TTL to avoid stalled locks::
187+
188+
use Symfony\Component\Lock\Store\MemcachedStore;
189+
190+
$memcached = new \Memcached();
191+
$memcached->addServer('localhost', 11211);
192+
193+
$store = new MemcachedStore($memcached);
194+
195+
.. note::
196+
197+
Memcached does not support TTL lower than 1 second.
198+
199+
.. _lock-store-redis:
200+
201+
RedisStore
202+
~~~~~~~~~~
203+
204+
The RedisStore saves locks on a Redis server, it requires a Redis connection
205+
implementing the ``\Redis``, ``\RedisArray``, ``\RedisCluster`` or
206+
``\Predis`` classes. This store does not support blocking, and expects a TTL to
207+
avoid stalled locks::
208+
209+
use Symfony\Component\Lock\Store\RedisStore;
210+
211+
$redis = new \Redis();
212+
$redis->connect('localhost');
213+
214+
$store = new RedisStore($redis);
215+
216+
.. _lock-store-semaphore:
217+
218+
SemaphoreStore
219+
~~~~~~~~~~~~~~
220+
221+
The SemaphoreStore uses the `PHP semaphore functions`_ to create the locks::
222+
223+
use Symfony\Component\Lock\Store\SemaphoreStore;
224+
225+
$store = new SemaphoreStore();
226+
227+
.. _lock-store-combined:
228+
229+
CombinedStore
230+
~~~~~~~~~~~~~
231+
232+
The CombinedStore is designed for High Availability applications because it
233+
manages several stores in sync (for example, several Redis servers). When a lock
234+
is being acquired, it forwards the call to all the managed stores, and it
235+
collects their responses. If a simple majority of stores have acquired the lock,
236+
then the lock is considered as acquired; otherwise as not acquired::
237+
238+
use Symfony\Component\Lock\Strategy\ConsensusStrategy;
239+
use Symfony\Component\Lock\Store\CombinedStore;
240+
use Symfony\Component\Lock\Store\RedisStore;
241+
242+
$stores = [];
243+
foreach (array('server1', 'server2', 'server3') as $server) {
244+
$redis= new \Redis();
245+
$redis->connect($server);
246+
247+
$stores[] = new RedisStore($redis);
248+
}
249+
250+
$store = new CombinedStore($stores, new ConsensusStrategy());
251+
252+
Instead of the simple majority strategy (``ConsensusStrategy``) an
253+
``UnanimousStrategy`` can be used to require the lock to be acquired in all
254+
the stores.
255+
256+
.. _`locks`: https://en.wikipedia.org/wiki/Lock_(computer_science)
257+
.. _Packagist: https://packagist.org/packages/symfony/lock
258+
.. _`PHP semaphore functions`: http://php.net/manual/en/book.sem.php

0 commit comments

Comments
 (0)
0