1
votes

in my application (ZF2 / ORM) i have 3 Entities (with Single Table inheritance)

User

Owner extends User

Agent extends User

i want to make one single Authentication (Login) for the 3 Entity using doctrine.authenticationservice.orm_default

module.config.php

 //other doctrine config 
    'authentication' => array(
        'orm_default' => array(
            'object_manager' => 'Doctrine\ORM\EntityManager',
            'identity_class' => 'Application\Entity\User',
            'identity_property' => 'email',
            'credential_property' => 'password',
            'credential_callable' => function(User $user, $passwordGiven) {
                return $user->getPassword() == md5($passwordGiven);
            },
        ),
    ),

and the process of login

//LoginController.php

// ..data validation 
            $this->authService = $this->getServiceLocator()->get('doctrine.authenticationservice.orm_default');
            $AuthAdapter = $this->authService->getAdapter();
            $AuthAdapter->setIdentity($this->request->getPost('email'));
            $AuthAdapter->setCredential(md5($this->request->getPost('password')));
            $result = $this->authService->authenticate();

            if($result->isValid()){
                $identity = $result->getIdentity();
                //continue                   
            }

how can i do this process without caring about object type, when i try to login with email of an Agent, i get this error

Catchable fatal error: Argument 1 passed to Application\Module::{closure}() must be an instance of User, instance of Application\Entity\Owner given

1

1 Answers

2
votes

The error you mention is due to the type hint on:

function(User $user) {

Which leads me to believe that you have a missing namespace declaration in your config file; in which case you can either add it or use the FQCN.

function(\Application\Entity\User $user) {

Nevertheless, I don't think it's actually the problem. You can only define one 'identity_class' with doctrine authentication (which the adapter will use to load the entity from the entity manager). If you have multiple entity classes there is no way to have each of these tested with one adapter.

However, the configuration is really just creating a new authentication adapter, specifically DoctrineModule\Authentication\Adapter\ObjectRepository. One solution would be to create multiple ObjectRepository adapters, each with the correct configuration for the different entities and then loop through each of them while calling authenticate() on the Zend\Authentication\AuthenticationService.

For example :

public function methodUsedToAutheticate($username, $password)
{
    // Assume we have an array of configured adapters in an array
    foreach($adapters as $adapter) {

        $adapter->setIdentity($username);
        $adapter->setCredential($password);

        // Authenticate using the new adapter
        $result = $authService->authenticate($adapter);

        if ($result->isValid()) {
            // auth success
            break;
        }
    }
    return $result; // auth failed
}

As previously mentioned is the doctrine config will not allow for more than one adapter, so you would need to create them manually and remove your current configuration.

Another example

public function getServiceConfig()
{
    return [
        'factories' => [
            'MyServiceThatDoesTheAuthetication' => function($sm) {

                $service = new MyServiceThatDoesTheAuthetication();

                // Assume some kind of api to add multiple adapters
                $service->addAuthAdapter($sm->get('AuthAdapterUser'));
                $service->addAuthAdapter($sm->get('AuthAdapterOwner'));
                $service->addAuthAdapter($sm->get('AuthAdapterAgent'));

                return $service;
            },
            'AuthAdapterAgent' => function($sm) {
                return new DoctrineModule\Authentication\Adapter\ObjectRepository(array(
                    'object_manager'      => $sm->get('ObjectManager'),
                    'identity_class'      => 'Application\Entity\Agent',
                    'identity_property'   => 'email',
                    'credential_property' => 'password'
                ));
            },
            'AuthAdapterOwner' => function($sm) {
                return new DoctrineModule\Authentication\Adapter\ObjectRepository(array(
                    'object_manager'      => $sm->get('ObjectManager'),
                    'identity_class'      => 'Application\Entity\Owner',
                    'identity_property'   => 'email',
                    'credential_property' => 'password'
                ));
            },
            // etc...
        ],
    ];
}

Hopefully this gives you some ideas as to what is required.

Lastly, if you would consider other modules, ZfcUser already has a 'chainable adapter' which actually does the above (but uses the event manager) so It might be worth taking a look at even if you don't use it.