Yuri Borges
Yuri Borges

Reputation: 325

User repository class as user provider and dependency injection

I'm following this tutorial (How to Authenticate Users with API Keys) to implement api keys in my application.

I'm using my user repository class which was created based on this tutorial (How to load Security Users from the Database) as the user provider that is needed in the pre authentication process, because that class already has the methods described as need from the user provider in the tutorial I'm following, namely loadUserByUsername(), refreshUser() and supportsClass().

Symfony calls my apikey_authenticator service which requires a user provider as argument. Because of that I've configured another service called userprovider that is my user repository class, like this:

services:
apikey_authenticator:
    class: MyBundle\Security\ApiKeyAuthenticator
    arguments: ["@userprovider"]
userprovider:
    class: MyBundle\Entity\UserRepository

But my user repository class is dependent on an entity manager, which I don't know how to inject. My doctrine's configuration is the default that comes with symfony:

# Doctrine Configuration
doctrine:
dbal:
    driver:   "%database_driver%"
    host:     "%database_host%"
    port:     "%database_port%"
    dbname:   "%database_name%"
    user:     "%database_user%"
    password: "%database_password%"
    charset:  UTF8

orm:
    auto_generate_proxy_classes: "%kernel.debug%"
    auto_mapping: true

How can I solve this? And is it a good idea using the user repository class as the user provider in this case?

Upvotes: 0

Views: 956

Answers (2)

Wcool
Wcool

Reputation: 329

Just wanted to add my 2c as I have followed those guides you mentioned too.

I have defined an Authenticator and provider class. The authenticator only does the necessary security checks and the provider handles the database connections (returning a user by token for instance).

In the __construct of my provider I have this:

protected $em;
protected $repositoryClass = 'myrepoclass';
protected $repository;

public function __construct(EntityManager $em) {
    $this->em = $em;
    $this->repository = $this->em->getRepository($this->repositoryClass);
}

Now I can just call queries like $this->repository->findOneById($id); I explicitly defined the repository class, because it allows easier switching to other entity if needed I think (could be wrong thinking ofcourse).

In my services file I have this:

api_user_provider:
  class: "%api_user_provider.class%"
  arguments: ["@doctrine.orm.entity_manager"]

api_user_authenticator:
  class: "%api_user_authenticator.class%"
  arguments: ["@api_user_provider"]

The provider class is not the same (at least for me) as the entity class. I separated them, because I think that works cleaner.

Well, that's how I have set things up. Hope this helps :)

edit: As I have created a separate bundle (ApiBundle and UserBundle), I have separated the provider from the entity class. I also followed the 'load security users from database' tutorial and this is the final thing I came up with to implement API token authentication. Although you do have the same methods already in your repository, I still think that it's better to separate it from your repository class as I did (that of course depends on your needs) as I think that works cleaner. Of course, the decision is up to you what to do :)

Upvotes: 1

Cerad
Cerad

Reputation: 48865

Doctrine entity repositories are created using a factory. Here is an example:

cerad_game__game_repository__doctrine:
    class:  Cerad\Bundle\GameBundle\Doctrine\EntityRepository\GameRepository
    factory_service: 'doctrine.orm.default_entity_manager'
    factory_method:  'getRepository'
    arguments:  
        - 'Cerad\Bundle\GameBundle\Doctrine\Entity\Game'

Is it a good idea? Might be cleaner to inject the repository into a UserProvider class instead of cluttering up the repository with the UserProvider methods. But either way will work.

Upvotes: 2

Related Questions