Skip to content

Commit f8da309

Browse files
committed
Merge branch '4.1'
* 4.1: Different way for updating flex projects Update sessions.rst Removed some repeated content and minor rewords doc(testing/http_authentication.rst); Update locale_sticky_session.rst Update form_collections.rst Add necessary call to Form::isSubmitted and remove boilerplate Undefined variable $userName in example [Cache] minor tweaks Fixed the code of the custom password authenticator example Documented PHPUnit data providers [Routing] do not install SensioFrameworkExtraBundle
2 parents c88ca04 + a5ab638 commit f8da309

17 files changed

+202
-154
lines changed

best_practices/tests.rst

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@ functional tests, you can quickly spot any big errors before you deploy them:
2727
Define a functional test that at least checks if your application pages
2828
are successfully loading.
2929

30-
A functional test can be as easy as this::
30+
A functional test like this is simple to implement thanks to
31+
:ref:`PHPUnit data providers <testing-data-providers>`::
3132

3233
// tests/ApplicationAvailabilityFunctionalTest.php
3334
namespace App\Tests;

components/cache.rst

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,9 @@ The Cache Component
1010

1111
The Cache component provides an extended `PSR-6`_ implementation as well as
1212
a `PSR-16`_ "Simple Cache" implementation for adding cache to your applications.
13-
It is designed to have a low overhead and it ships with ready to use adapters
14-
for the most common caching backends.
13+
It is designed for performance and resiliency, and ships with ready to use
14+
adapters for the most common caching backends, including proxies for adapting
15+
from/to `Doctrine Cache`_.
1516

1617
Installation
1718
------------
@@ -189,4 +190,4 @@ Advanced Usage (PSR-6)
189190

190191
.. _`PSR-6`: http://www.php-fig.org/psr/psr-6/
191192
.. _`PSR-16`: http://www.php-fig.org/psr/psr-16/
192-
.. _Packagist: https://packagist.org/packages/symfony/cache
193+
.. _Doctrine Cache: https://www.doctrine-project.org/projects/cache.html

components/cache/adapters/pdo_doctrine_dbal_adapter.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ third, and forth parameters::
2727
// until the database table is truncated or its rows are otherwise deleted)
2828
$defaultLifetime = 0,
2929

30-
// an array of options for configuring the database connection
30+
// an array of options for configuring the database table and connection
3131
$options = array()
3232
);
3333

components/cache/cache_invalidation.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,15 @@ several cached items, keeping them in sync can be difficult.
1212

1313
The Symfony Cache component provides two mechanisms to help solving this problem:
1414

15-
* :ref:`Tags based invalidation <cache-component-tags>` for managing data dependencies;
15+
* :ref:`Tags-based invalidation <cache-component-tags>` for managing data dependencies;
1616
* :ref:`Expiration based invalidation <cache-component-expiration>` for time related dependencies.
1717

1818
.. _cache-component-tags:
1919

2020
Using Cache Tags
2121
----------------
2222

23-
To benefit from tags based invalidation, you need to attach the proper tags to
23+
To benefit from tags-based invalidation, you need to attach the proper tags to
2424
each cached item. Each tag is a plain string identifier that you can use at any
2525
time to trigger the removal of all items associated with this tag.
2626

components/cache/cache_pools.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,7 @@ allowing manual removal of stale cache items::
184184

185185
The :ref:`ChainAdapter <component-cache-chain-adapter>` implementation does not directly
186186
contain any pruning logic itself. Instead, when calling the chain adapter's
187-
:method:`Symfony\\Component\\Cache\\ChainAdapter::prune` method, the call is delegated to all
187+
:method:`Symfony\\Component\\Cache\\Adapter\\ChainAdapter::prune` method, the call is delegated to all
188188
its compatible cache adapters (and those that do not implement ``PruneableInterface`` are
189189
silently ignored)::
190190

components/http_foundation/sessions.rst

Lines changed: 57 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -94,29 +94,12 @@ Session Workflow
9494
Session Attributes
9595
..................
9696

97-
:method:`Symfony\\Component\\HttpFoundation\\Session\\Session::set`
98-
Sets an attribute by key.
97+
The session attributes are stored internally in a "Bag", a PHP object that acts
98+
like an array. They can be set, removed, checked, etc. using the methods
99+
explained later in this article for the ``AttributeBagInterface`` class. See
100+
:ref:`attribute-bag-interface`.
99101

100-
:method:`Symfony\\Component\\HttpFoundation\\Session\\Session::get`
101-
Gets an attribute by key.
102-
103-
:method:`Symfony\\Component\\HttpFoundation\\Session\\Session::all`
104-
Gets all attributes as an array of key => value.
105-
106-
:method:`Symfony\\Component\\HttpFoundation\\Session\\Session::has`
107-
Returns true if the attribute exists.
108-
109-
:method:`Symfony\\Component\\HttpFoundation\\Session\\Session::replace`
110-
Sets multiple attributes at once: takes a keyed array and sets each key => value pair.
111-
112-
:method:`Symfony\\Component\\HttpFoundation\\Session\\Session::remove`
113-
Deletes an attribute by key.
114-
115-
:method:`Symfony\\Component\\HttpFoundation\\Session\\Session::clear`
116-
Clear all attributes.
117-
118-
The attributes are stored internally in a "Bag", a PHP object that acts like
119-
an array. A few methods exist for "Bag" management:
102+
In addition, a few methods exist for "Bag" management:
120103

121104
:method:`Symfony\\Component\\HttpFoundation\\Session\\Session::registerBag`
122105
Registers a :class:`Symfony\\Component\\HttpFoundation\\Session\\SessionBagInterface`.
@@ -168,19 +151,65 @@ the following API which is intended mainly for internal purposes:
168151
:method:`Symfony\\Component\\HttpFoundation\\Session\\SessionBagInterface::getName`
169152
Returns the name of the session bag.
170153

154+
.. _attribute-bag-interface:
155+
171156
Attributes
172157
~~~~~~~~~~
173158

174159
The purpose of the bags implementing the :class:`Symfony\\Component\\HttpFoundation\\Session\\Attribute\\AttributeBagInterface`
175160
is to handle session attribute storage. This might include things like user ID,
176-
and remember me login settings or other user based state information.
161+
and "Remember Me" login settings or other user based state information.
177162

178163
:class:`Symfony\\Component\\HttpFoundation\\Session\\Attribute\\AttributeBag`
179164
This is the standard default implementation.
180165

181166
:class:`Symfony\\Component\\HttpFoundation\\Session\\Attribute\\NamespacedAttributeBag`
182167
This implementation allows for attributes to be stored in a structured namespace.
183168

169+
:class:`Symfony\\Component\\HttpFoundation\\Session\\Attribute\\AttributeBagInterface`
170+
has a simple API
171+
172+
:method:`Symfony\\Component\\HttpFoundation\\Session\\Attribute\\AttributeBagInterface::set`
173+
Sets an attribute by name (``set('name', 'value')``).
174+
175+
:method:`Symfony\\Component\\HttpFoundation\\Session\\Attribute\\AttributeBagInterface::get`
176+
Gets an attribute by name (``get('name')``) and can define a default
177+
value when the attribute doesn't exist (``get('name', 'default_value')``).
178+
179+
:method:`Symfony\\Component\\HttpFoundation\\Session\\Attribute\\AttributeBagInterface::all`
180+
Gets all attributes as an associative array of ``name => value``.
181+
182+
:method:`Symfony\\Component\\HttpFoundation\\Session\\Attribute\\AttributeBagInterface::has`
183+
Returns ``true`` if the attribute exists.
184+
185+
:method:`Symfony\\Component\\HttpFoundation\\Session\\Attribute\\AttributeBagInterface::replace`
186+
Sets multiple attributes at once using an associative array (``name => value``).
187+
If the attributes existed, they are replaced; if not, they are created.
188+
189+
:method:`Symfony\\Component\\HttpFoundation\\Session\\Attribute\\AttributeBagInterface::remove`
190+
Deletes an attribute by name and returns its value.
191+
192+
:method:`Symfony\\Component\\HttpFoundation\\Session\\Attribute\\AttributeBagInterface::clear`
193+
Deletes all attributes.
194+
195+
Example::
196+
197+
use Symfony\Component\HttpFoundation\Session\Attribute\AttributeBag;
198+
use Symfony\Component\HttpFoundation\Session\Session;
199+
use Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage;
200+
201+
$session = new Session(new NativeSessionStorage(), new AttributeBag());
202+
$session->set('token', 'a6c1e0b6');
203+
// ...
204+
$token = $session->get('token');
205+
// if the attribute may or may not exist, you can define a default value for it
206+
$token = $session->get('attribute-name', 'default-attribute-value');
207+
// ...
208+
$session->clear();
209+
210+
Namespaced Attributes
211+
.....................
212+
184213
Any plain key-value storage system is limited in the extent to which
185214
complex data can be stored since each key must be unique. You can achieve
186215
namespacing by introducing a naming convention to the keys so different parts of
@@ -205,35 +234,13 @@ the array::
205234
$session->set('tokens', $tokens);
206235

207236
With structured namespacing, the key can be translated to the array
208-
structure like this using a namespace character (defaults to ``/``)::
209-
210-
$session->set('tokens/c', $value);
211-
212-
This way you can easily access a key within the stored array directly and easily.
213-
214-
:class:`Symfony\\Component\\HttpFoundation\\Session\\Attribute\\AttributeBagInterface`
215-
has a simple API
216-
217-
:method:`Symfony\\Component\\HttpFoundation\\Session\\Attribute\\AttributeBagInterface::set`
218-
Sets an attribute by key.
219-
220-
:method:`Symfony\\Component\\HttpFoundation\\Session\\Attribute\\AttributeBagInterface::get`
221-
Gets an attribute by key.
222-
223-
:method:`Symfony\\Component\\HttpFoundation\\Session\\Attribute\\AttributeBagInterface::all`
224-
Gets all attributes as an array of key => value.
225-
226-
:method:`Symfony\\Component\\HttpFoundation\\Session\\Attribute\\AttributeBagInterface::has`
227-
Returns true if the attribute exists.
228-
229-
:method:`Symfony\\Component\\HttpFoundation\\Session\\Attribute\\AttributeBagInterface::replace`
230-
Sets multiple attributes at once: takes a keyed array and sets each key => value pair.
237+
structure like this using a namespace character (which defaults to ``/``)::
231238

232-
:method:`Symfony\\Component\\HttpFoundation\\Session\\Attribute\\AttributeBagInterface::remove`
233-
Deletes an attribute by key.
239+
// ...
240+
use Symfony\Component\HttpFoundation\Session\Attribute\NamespacedAttributeBag;
234241

235-
:method:`Symfony\\Component\\HttpFoundation\\Session\\Attribute\\AttributeBagInterface::clear`
236-
Clear the bag.
242+
$session = new Session(new NativeSessionStorage(), new NamespacedAttributeBag());
243+
$session->set('tokens/c', $value);
237244

238245
Flash Messages
239246
~~~~~~~~~~~~~~

form/form_collections.rst

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -655,12 +655,9 @@ the relationship between the removed ``Tag`` and ``Task`` object.
655655
use Doctrine\Common\Collections\ArrayCollection;
656656

657657
// ...
658-
public function edit($id, Request $request)
658+
public function edit($id, Request $request, EntityManagerInterface $entityManager)
659659
{
660-
$entityManager = $this->getDoctrine()->getManager();
661-
$task = $entityManager->getRepository(Task::class)->find($id);
662-
663-
if (!$task) {
660+
if (null === $task = $entityManager->getRepository(Task::class)->find($id)) {
664661
throw $this->createNotFoundException('No task found for id '.$id);
665662
}
666663

@@ -675,8 +672,7 @@ the relationship between the removed ``Tag`` and ``Task`` object.
675672

676673
$editForm->handleRequest($request);
677674

678-
if ($editForm->isValid()) {
679-
675+
if ($editForm->isSubmitted() && $editForm->isValid()) {
680676
// remove the relationship between the tag and the Task
681677
foreach ($originalTags as $tag) {
682678
if (false === $task->getTags()->contains($tag)) {

form/unit_testing.rst

Lines changed: 5 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,11 @@ widgets you want to display are available in the children property::
107107
$this->assertArrayHasKey($key, $children);
108108
}
109109

110+
.. tip::
111+
112+
Use :ref:`PHPUnit data providers <testing-data-providers>` to test multiple
113+
form conditions using the same test code.
114+
110115
Testings Types from the Service Container
111116
-----------------------------------------
112117

@@ -213,56 +218,3 @@ guessers using the :method:`Symfony\\Component\\Form\\Test\\FormIntegrationTestC
213218
:method:`Symfony\\Component\\Form\\Test\\FormIntegrationTestCase::getTypeExtensions`
214219
and :method:`Symfony\\Component\\Form\\Test\\FormIntegrationTestCase::getTypeGuessers`
215220
methods.
216-
217-
Testing against Different Sets of Data
218-
--------------------------------------
219-
220-
If you are not familiar yet with PHPUnit's `data providers`_, this might be
221-
a good opportunity to use them::
222-
223-
// tests/Form/Type/TestedTypeTest.php
224-
namespace App\Tests\Form\Type;
225-
226-
use App\Form\Type\TestedType;
227-
use Symfony\Component\Form\Test\TypeTestCase;
228-
229-
class TestedTypeTest extends TypeTestCase
230-
{
231-
/**
232-
* @dataProvider getValidTestData
233-
*/
234-
public function testForm($data)
235-
{
236-
// ... your test
237-
}
238-
239-
public function getValidTestData()
240-
{
241-
return array(
242-
array(
243-
'data' => array(
244-
'test' => 'test',
245-
'test2' => 'test2',
246-
),
247-
),
248-
array(
249-
'data' => array(),
250-
),
251-
array(
252-
'data' => array(
253-
'test' => null,
254-
'test2' => null,
255-
),
256-
),
257-
);
258-
}
259-
}
260-
261-
The code above will run your test three times with 3 different sets of
262-
data. This allows for decoupling the test fixtures from the tests and
263-
easily testing against multiple sets of data.
264-
265-
You can also pass another argument, such as a boolean if the form has to
266-
be synchronized with the given set of data or not etc.
267-
268-
.. _`data providers`: https://phpunit.de/manual/current/en/writing-tests-for-phpunit.html#writing-tests-for-phpunit.data-providers

routing.rst

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,19 @@ the change is simple.
2020
Creating Routes
2121
---------------
2222

23-
First, add support for annotations via the SensioFrameworkExtraBundle:
23+
A *route* is a map from a URL path to a controller. Suppose you want one route that
24+
matches ``/blog`` exactly and another more dynamic route that can match *any* URL
25+
like ``/blog/my-post`` or ``/blog/all-about-symfony``.
26+
27+
Routes can be configured in YAML, XML and PHP. All formats provide the same
28+
features and performance, so choose the one you prefer. If you choose PHP
29+
annotations, run this command once in your app to add support for them:
2430

2531
.. code-block:: terminal
2632
27-
$ composer require sensio/framework-extra-bundle
33+
$ composer require annotations
2834
29-
A *route* is a map from a URL path to a controller. Suppose you want one route that
30-
matches ``/blog`` exactly and another more dynamic route that can match *any* URL
31-
like ``/blog/my-post`` or ``/blog/all-about-symfony``:
35+
Now you can configure the routes:
3236

3337
.. configuration-block::
3438

security/custom_password_authenticator.rst

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ the user::
2828
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
2929
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
3030
use Symfony\Component\Security\Core\Encoder\UserPasswordEncoderInterface;
31+
use Symfony\Component\Security\Core\Exception\BadCredentialsException;
3132
use Symfony\Component\Security\Core\Exception\CustomUserMessageAuthenticationException;
3233
use Symfony\Component\Security\Core\Exception\UsernameNotFoundException;
3334
use Symfony\Component\Security\Core\User\UserProviderInterface;
@@ -52,7 +53,20 @@ the user::
5253
throw new CustomUserMessageAuthenticationException('Invalid username or password');
5354
}
5455

55-
$isPasswordValid = $this->encoder->isPasswordValid($user, $token->getCredentials());
56+
$currentUser = $token->getUser();
57+
58+
if ($currentUser instanceof UserInterface) {
59+
if ($currentUser->getPassword() !== $user->getPassword()) {
60+
throw new BadCredentialsException('The credentials were changed from another session.');
61+
}
62+
} else {
63+
if ('' === ($givenPassword = $token->getCredentials())) {
64+
throw new BadCredentialsException('The given password cannot be empty.');
65+
}
66+
if (!$this->encoderFactory->getEncoder($user)->isPasswordValid($user->getPassword(), $givenPassword, $user->getSalt())) {
67+
throw new BadCredentialsException('The given password is invalid.');
68+
}
69+
}
5670

5771
if ($isPasswordValid) {
5872
$currentHour = date('G');

security/custom_provider.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,8 @@ Here's an example of how this might look::
144144
);
145145
}
146146

147+
$username = $user->getUsername();
148+
147149
return $this->fetchUser($username);
148150
}
149151

0 commit comments

Comments
 (0)