title: How to get a Custom User Provider working in Silex?
body: <p>I could really use a second pair of eyes. I am attempting to create a custom user provider using Silex's <a href="http://silex.sensiolabs.org/doc/providers/security.html#defining-a-custom-user-provider" rel="nofollow">SecurityServiceProvider</a> in conjunction with Doctrine MongoDB ODM, and I keep receiving the following error when attempting to log in:</p>
  
  <pre><code>RuntimeException in ContextListener.php line 177:
  There is no user provider for user "FooBar\Document\User".
  </code></pre>
  
  <p>Note: If I hard-code the users, it works perfectly</p>
  
  <pre><code>'users' =&gt; [
      'admin' =&gt; [
          'ROLE_ADMIN', '$2y$12$W6FYYG1YTdMUNSosk14jluYsCwTe5wL7qwi3bnRMsqQEShb.89OiG'
      ],
  ]
  </code></pre>
  
  <p>As far as I can tell, I have followed the Silex documentation, which can be found <a href="http://silex.sensiolabs.org/doc/providers/security.html#defining-a-custom-user-provider" rel="nofollow">here</a>. I verified that it is successfully fetching the user from the db, so I know that is not the issue. Below is the pertinent code, including snippets from app.php, the user class, and my custom user provider class.</p>
  
  <pre><code>$app-&gt;register(new Neutron\Silex\Provider\MongoDBODMServiceProvider(), $dbConfig);
  
  // Create document manager alias
  $app['dm'] = $app['doctrine.odm.mongodb.dm'];
  
  $app-&gt;register(new Silex\Provider\SecurityServiceProvider(), [
      'security.firewalls' =&gt; [
          'login' =&gt; [
              'pattern' =&gt; '^/login$',
              'anonymous' =&gt; true
          ],
          'secured' =&gt; [
              'pattern' =&gt; '^.*$',
              'form' =&gt; [
                  'login_path' =&gt; '/login',
                  'check_path' =&gt; '/login/authenticate',
              ],
              'logout' =&gt; [
                  'logout_path' =&gt; '/logout',
                  'target' =&gt; '/'
              ],
              'users' =&gt; $app-&gt;share(function() use ($app) {
                  return new \FooBar\Repository\UserRepository($app['dm']);
              })
          ],
          'unsecured' =&gt; [
              'anonymous' =&gt; true
          ]
      ],
      'security.role_hierarchy' =&gt; [
          'ROLE_ADMIN' =&gt; [
              'ROLE_USER',
          ],
          'ROLE_SUPER_ADMIN' =&gt; [
              'ROLE_ADMIN',
              'ROLE_ALLOWED_TO_SWITCH'
          ]
      ],
      'security.access_rules' =&gt; [
          ['^/login', 'IS_AUTHENTICATED_ANONYMOUSLY'],
          ['^.*', 'ROLE_USER']
      ]
  ]);
  
  $app['security.encoder.digest'] = $app-&gt;share(function() {
      return new Symfony\Component\Security\Core\Encoder\BCryptPasswordEncoder(12);
  });
  </code></pre>
  
  <hr>
  
  <p>
  
  <pre><code>namespace FooBar\Repository;
  
  use Symfony\Component\Security\Core\User\UserInterface;
  use Symfony\Component\Security\Core\User\UserProviderInterface;
  use Symfony\Component\Security\Core\Exception\UsernameNotFoundException;
  use Symfony\Component\Security\Core\Exception\UnsupportedUserException;
  
  class UserRepository implements UserProviderInterface
  {
      public function loadUserByUsername($username)
      {
          try {
  
              $user = $this-&gt;dm-&gt;createQueryBuilder('\FooBar\Document\User')
                  -&gt;field('username')-&gt;equals($username)
                  -&gt;getQuery()
                  -&gt;getSingleResult();
  
          } catch (NoResultException $e) {
  
              throw new UsernameNotFoundException(sprintf(
                  'Unable to find an active User object identified by "%s".',
                  $username
              ), 0, $e);
  
          }
  
          return $user;
      }
  
      public function refreshUser(UserInterface $user)
      {
          $class = get_class($user);
  
          if (!$this-&gt;supportsClass($class)) {
              throw new UnsupportedUserException(sprintf('Instances of "%s" are not supported.', $class));
          }
  
          return $this-&gt;loadUserByUsername($user-&gt;getUsername());
      }
  
      public function supportsClass($class)
      {
          return $class === '\FooBar\Document\User' || is_subclass_of($class, '\FooBar\Document\User');
      }
  }
  </code></pre>
  
  <hr>
  
  <pre><code>&lt;?php
  
  namespace FooBar\Document;
  
  use Doctrine\Common\Collections\ArrayCollection;
  use Doctrine\ODM\MongoDB\Mapping\Annotations as ODM;
  use Symfony\Component\Security\Core\User\AdvancedUserInterface;
  
  /**
   * @ODM\Document(repositoryClass="FooBar\Repository\UserRepository")
   */
  class User implements AdvancedUserInterface
  {
      /**
       * Document Id
       * @ODM\Id
       */
      protected $id;
  
      /**
       * User first name
       * @ODM\String
       */
      protected $firstName;
  
      /**
       * User last name
       * @ODM\String
       */
      protected $lastName;
  
      /**
       * User email
       * @ODM\String
       * @ODM\UniqueIndex
       */
      protected $email;
  
      /**
       * User username
       * @ODM\String
       * @ODM\UniqueIndex
       */
      protected $username;
  
      /**
       * User password
       * @ODM\String
       */
      protected $password;
  
      /**
       * Whether or not user account is expired
       * @ODM\Boolean
       */
      protected $isAccountExpired;
  
      /**
       * Whether or not user account is locked
       * @ODM\Boolean
       */
      protected $isAccountLocked;
  
      /**
       * Whether or not user credentials are expired
       * @ODM\Boolean
       */
      protected $isCredentialsExpired;
  
      /**
       * Whether or not user is active
       * @ODM\Boolean
       */
      protected $isActive;
  
      /**
       * Whether or not user credentials are erased
       * @ODM\Boolean
       */
      protected $isCredentialsErased;
  
      /**
       * User roles
       * @ODM\Collection
       */
      protected $roles;
  /
      public function __construct()
      {
          parent::__construct();
          $this-&gt;isActive = true;
          $this-&gt;isAccountLocked = false;
          $this-&gt;isAccountExpired = false;
          $this-&gt;isCredentialsExpired = false;
          $this-&gt;isCredentialsErased = false;
          $this-&gt;roles = new ArrayCollection;
  
          // Temporary
          $this-&gt;roles = ['ROLE_USER'];
      }
  
      public function setFirstName($firstName)
      {
          $this-&gt;firstName = $firstName;
      }
  
      public function setLastName($lastName)
      {
          $this-&gt;lastName = $lastName;    
      }
  
      public function setEmail($email)
      {
          $this-&gt;email = ($email);
      }
  
      public function setUsername($username)
      {
          $this-&gt;username = $username;
      }
  
      public function setPassword($password)
      {
          $this-&gt;password = $password;
      }
  
      public function getFirstName()
      {
          return $this-&gt;firstName;
      }
  
      public function getLastName()
      {
          return $this-&gt;lastName;
      }
  
      public function getEmail()
      {
          return $this-&gt;email;
      }
  
      public function getUsername()
      {
          return $this-&gt;username;
      }
  
      public function getPassword()
      {
          return $this-&gt;password;
      }
  
      public function getSalt()
      {
          return null;
      }
  
      public function getRoles()
      {
          return $this-&gt;roles;
      }
  
      public function isAccountNonExpired()
      {
          return !$this-&gt;isAccountExpired;
      }
  
      public function isAccountNonLocked()
      {
          return !$this-&gt;isAccountLocked;
      }
  
      public function isCredentialsNonExpired()
      {
          return !$this-&gt;isCredentialsExpired;
      }
  
      public function isCredentialsErased()
      {
          return $this-&gt;isCredentialsErased;
      }
  
      public function isEnabled()
      {
          return $this-&gt;isActive;
      }
  
      public function eraseCredentials()
      {
          $this-&gt;username = null;
          $this-&gt;password = null;
          $this-&gt;isActive = false;
          $this-&gt;isAccountLocked = true;
          $this-&gt;isAccountExpired = true;
          $this-&gt;isCredentialsExpired = true;
          $this-&gt;isCredentialsErased = true;
  
          return $this;
      }
  
      public function serialize()
      {
          return serialize([
              $this-&gt;id,
              $this-&gt;firstName,
              $this-&gt;lastName,
              $this-&gt;email,
              $this-&gt;username,
          ]);
      }
  
      public function unserialize($serialized)
      {
          list(
              $this-&gt;id,
              $this-&gt;firstName,
              $this-&gt;lastName,
              $this-&gt;email,
              $this-&gt;username,
          ) = unserialize($serialized);
      }
  }
  </code></pre>