Skip to content

Commit

Permalink
require a user object
Browse files Browse the repository at this point in the history
  • Loading branch information
jrushlow committed Mar 5, 2024
1 parent 239a9ad commit b00491a
Show file tree
Hide file tree
Showing 5 changed files with 41 additions and 33 deletions.
42 changes: 35 additions & 7 deletions README.md
Expand Up @@ -112,21 +112,49 @@ requests that may have been left in persistence.
The `ResetPasswordRequestRepositoryInterface::removeRequests()` method, which is
implemented in the
[ResetPasswordRequestRepositoryTrait](https://github.com/SymfonyCasts/reset-password-bundle/blob/main/src/Persistence/Repository/ResetPasswordRequestRepositoryTrait.php),
can be used to remove request objects from persistence for a single user or all
users. This differs from the
can be used to remove all request objects from persistence for a single user. This
differs from the
[garbage collection mechanism](https://github.com/SymfonyCasts/reset-password-bundle/blob/df64d82cca2ee371da5e8c03c227457069ae663e/src/Persistence/Repository/ResetPasswordRequestRepositoryTrait.php#L73)
which only removes _expired_ request objects for _all_ users automatically.

Typically, you'd call this method when you need to remove request object(s) for
a user who changed their email address due to suspicious activity and potentially
has valid request objects in persistence with their "old" compromised email address.
In such cases, pass the `user` object to `removeRequest()`.

Passing `null` or omitting a `user` object will remove all request objects from
persistence - even if any of those requests have not expired.

This method relies on the user objects `primary key` being `immutable`.
E.g. `User::id = UUID` not something like `User::id = 'john@example.com'`
E.g. `User::id = UUID` not something like `User::id = 'john@example.com'`.

```php
// ProfileController

#[Route(path: '/profile/{id}', name: 'app_update_profile', methods: ['GET', 'POST'])]
public function profile(Request $request, User $user, ResetPasswordRequestRepositoryInterface $repository): Response
{
$form = $this->createFormBuilder($user)
->add('email', EmailType::class)
->add('save', SubmitType::class, ['label' => 'Save Profile'])
->getForm()
;

$form->handleRequest($request);

if ($form->isSubmitted() && $form->isValid()) {
$newEmail = $form->get('email')->getData();

if ($newEmail !== $user->getEmail()) {
// The user changed their email address.
// Remove any old reset requests for the user.
$repository->removeRequests($user);
}

// Persist the user object...

return $this->render('success.html.twig');
}

return $this->render('profile.html.twig', ['form' => $form]);
}
```

## Support

Expand Down
Expand Up @@ -61,7 +61,7 @@ public function removeExpiredResetPasswordRequests(): int
throw new FakeRepositoryException();
}

public function removeRequests(?object $user = null): void
public function removeRequests(object $user): void
{
throw new FakeRepositoryException();
}
Expand Down
16 changes: 4 additions & 12 deletions src/Persistence/Repository/ResetPasswordRequestRepositoryTrait.php
Expand Up @@ -84,30 +84,22 @@ public function removeExpiredResetPasswordRequests(): int
}

/**
* Remove ResetPasswordRequest objects from persistence.
* Remove a users ResetPasswordRequest objects from persistence.
*
* Warning - This is a destructive operation. Calling this method
* may have undesired consequences for users who have valid
* ResetPasswordRequests but have not "checked their email" yet.
*
* If a "user" object is passed, only the requests for that user
* will be removed.
*
* @see https://github.com/SymfonyCasts/reset-password-bundle?tab=readme-ov-file#advanced-usage
*/
public function removeRequests(?object $user = null): void
public function removeRequests(object $user): void
{
$query = $this->createQueryBuilder('t')
->delete()
->where('t.user = :user')
->setParameter('user', $user)
;

if (null !== $user) {
$query
->where('t.user = :user')
->setParameter('user', $user)
;
}

$query->getQuery()->execute();
}
}
Expand Up @@ -15,7 +15,7 @@
* @author Jesse Rushlow <jr@rushlow.dev>
* @author Ryan Weaver <ryan@symfonycasts.com>
*
* @method void removeRequests(?object $user = null) Remove ResetPasswordRequest objects from persistence.
* @method void removeRequests(object $user) Remove a users ResetPasswordRequest objects from persistence.
*/
interface ResetPasswordRequestRepositoryInterface
{
Expand Down
Expand Up @@ -208,18 +208,6 @@ public function testRemovedExpiredResetPasswordRequestsOnlyRemovedExpiredRequest
self::assertSame($futureFixture, $result[0]);
}

public function testRemoveRequestsRemovesAllRequestsFromPersistence(): void
{
$this->manager->persist(new ResetPasswordTestFixtureRequest());
$this->manager->persist(new ResetPasswordTestFixtureRequest());

$this->manager->flush();

$this->repository->removeRequests();

self::assertCount(0, $this->repository->findAll());
}

public function testRemoveRequestsRemovesAllRequestsForASingleUser(): void
{
$this->manager->persist($userFixture = new ResetPasswordTestFixtureUser());
Expand Down

0 comments on commit b00491a

Please sign in to comment.