ChainUserProvider.php 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. <?php
  2. /*
  3. * This file is part of the Symfony package.
  4. *
  5. * (c) Fabien Potencier <fabien@symfony.com>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Symfony\Component\Security\Core\User;
  11. use Symfony\Component\Security\Core\Exception\UnsupportedUserException;
  12. use Symfony\Component\Security\Core\Exception\UsernameNotFoundException;
  13. /**
  14. * Chain User Provider.
  15. *
  16. * This provider calls several leaf providers in a chain until one is able to
  17. * handle the request.
  18. *
  19. * @author Johannes M. Schmitt <schmittjoh@gmail.com>
  20. */
  21. class ChainUserProvider implements UserProviderInterface, PasswordUpgraderInterface
  22. {
  23. private $providers;
  24. /**
  25. * @param iterable|UserProviderInterface[] $providers
  26. */
  27. public function __construct(iterable $providers)
  28. {
  29. $this->providers = $providers;
  30. }
  31. /**
  32. * @return array
  33. */
  34. public function getProviders()
  35. {
  36. if ($this->providers instanceof \Traversable) {
  37. return iterator_to_array($this->providers);
  38. }
  39. return $this->providers;
  40. }
  41. /**
  42. * {@inheritdoc}
  43. */
  44. public function loadUserByUsername(string $username)
  45. {
  46. foreach ($this->providers as $provider) {
  47. try {
  48. return $provider->loadUserByUsername($username);
  49. } catch (UsernameNotFoundException $e) {
  50. // try next one
  51. }
  52. }
  53. $ex = new UsernameNotFoundException(sprintf('There is no user with name "%s".', $username));
  54. $ex->setUsername($username);
  55. throw $ex;
  56. }
  57. /**
  58. * {@inheritdoc}
  59. */
  60. public function refreshUser(UserInterface $user)
  61. {
  62. $supportedUserFound = false;
  63. foreach ($this->providers as $provider) {
  64. try {
  65. if (!$provider->supportsClass(\get_class($user))) {
  66. continue;
  67. }
  68. return $provider->refreshUser($user);
  69. } catch (UnsupportedUserException $e) {
  70. // try next one
  71. } catch (UsernameNotFoundException $e) {
  72. $supportedUserFound = true;
  73. // try next one
  74. }
  75. }
  76. if ($supportedUserFound) {
  77. $e = new UsernameNotFoundException(sprintf('There is no user with name "%s".', $user->getUsername()));
  78. $e->setUsername($user->getUsername());
  79. throw $e;
  80. } else {
  81. throw new UnsupportedUserException(sprintf('There is no user provider for user "%s". Shouldn\'t the "supportsClass()" method of your user provider return true for this classname?', get_debug_type($user)));
  82. }
  83. }
  84. /**
  85. * {@inheritdoc}
  86. */
  87. public function supportsClass(string $class)
  88. {
  89. foreach ($this->providers as $provider) {
  90. if ($provider->supportsClass($class)) {
  91. return true;
  92. }
  93. }
  94. return false;
  95. }
  96. /**
  97. * {@inheritdoc}
  98. */
  99. public function upgradePassword(UserInterface $user, string $newEncodedPassword): void
  100. {
  101. foreach ($this->providers as $provider) {
  102. if ($provider instanceof PasswordUpgraderInterface) {
  103. try {
  104. $provider->upgradePassword($user, $newEncodedPassword);
  105. } catch (UnsupportedUserException $e) {
  106. // ignore: password upgrades are opportunistic
  107. }
  108. }
  109. }
  110. }
  111. }