Search code examples
phpsymfonysymfony-security

Symfony 3 login by array of phones


Good Day! I want to login my users and it's a trivial task. But issue is checking user by array of values!

For example I have entity user and phone. User have many phones. So I need to login user by all of phones which it has. How can I do it using default tool of security bundle?

I didn't find any question like my one and read all documentation about security in Symfony. The only thing which I thought to do is creating custom provider. But I don't think it solves my problem.

Any ides, dear symfoners? :)


Solution

  • You have to set a security provider in security.yml

    security:
    
        # http://symfony.com/doc/current/book/security.html#where-do-users-come-from-user-providers
    ...
    
        providers:
            my_db_provider:
                entity:
                    class: AppBundle:User
    ...
    

    Then your entity AppBundle:User should implements the interface Symfony\Component\Security\Core\User\UserInterface and have a custom repository for Example UserRepository that implements the interface Symfony\Bridge\Doctrine\Security\User\UserLoaderInterface. Your UserRepository class should look like this:

    <?php
    
    use Doctrine\ORM\NonUniqueResultException;
    use Doctrine\ORM\NoResultException;
    use AppBundle\Entity\User;
    use Symfony\Bridge\Doctrine\Security\User\UserLoaderInterface;
    use Symfony\Component\Security\Core\Exception\UsernameNotFoundException;
    
    class UserRepository extends EntityRepository implements UserLoaderInterface
    {
    
     /**
      * Loads the user for the given username.
      *
      * This method must return null if the user is not found.
      *
      * @param string $username The username
      * @return null|Utilisateur
      * @throws \Exception
      */
      public function loadUserByUsername($username)
      {
        //Here you write a custom query to retrive the user base on the fields you require. 
        // Here I have used username, email and phone number
        $q = $this
            ->createQueryBuilder('u')
            ->select('u')
            ->leftJoin('u.phones', 'p')
            ->where('u.username = :username or u.email= :email or p.phoneNumber= :phone')
            ->setParameter('username', $username)
            ->setParameter('email', $username)
            ->setParameter('phone ', $username)
            ->getQuery();
        try {
            $user = $q->getSingleResult();
        } catch (NoResultException $e) {
            throw new UsernameNotFoundException(sprintf('Unable to find an active user AppBundle:User object identified by "%s".', $username), 0, $e);
        } catch (NonUniqueResultException $ex) {
            throw new \Exception("The user you provided is not unique");
        }
        return $user;
      }
    }
    

    Your AppByndle:User entity class should look like this:

    <?php
    
    
      use Doctrine\Common\Collections\ArrayCollection;
      use Doctrine\Common\Collections\Collection;
      use Doctrine\ORM\Mapping as ORM;
      use Symfony\Component\Security\Core\User\UserInterface;
    
      /**
       * User
       *
       * @ORM\Table(name="user")
       * @ORM\Entity(repositoryClass="AppBundle\Dao\UserRepository")
     */
     class User implements UserInterface
     {
      /**
       * @var integer
       *
       * @ORM\Column(name="id", type="integer", nullable=false)
       * @ORM\Id
       * @ORM\GeneratedValue(strategy="IDENTITY")
       */
       private $id;
    
       /**
        * @var string
        *
        * @ORM\Column(name="username", type="string", length=254, nullable=false, unique=true)
        */
        private $username;
    
        ....
        ....
    
      }